Tôi thấy các câu trả lời khác khó hiểu nên tôi quyết định giải thích nó bằng một ví dụ thực tế. Giả sử heap ban đầu là kích thước N và bạn muốn tìm các phần tử lớn nhất thứ k, Giải pháp này có thời gian O (klogk) và không gian O (k).
10
/\
5 3
/\ /\
4 1 2 0
Original Heap, N = 7
Muốn tìm phần tử lớn thứ 5. k = 5 Lưu ý: Trong heap mới, bạn cần lưu con trỏ vào heap gốc. Điều này có nghĩa là bạn không xóa hoặc thay đổi vùng gốc. Vùng heap ban đầu là chỉ đọc. Do đó, bạn không bao giờ phải thực hiện bất kỳ thao tác nào yêu cầu thời gian O (logN).
Cho x 'là con trỏ đến giá trị x trong vùng gốc.
Iteration 1: Nhận con trỏ nút gốc của thành đống mới
Bước 1: Thêm con trỏ đến nút 10
10'
New Heap, size = 1, root = 10', root->left = 5, root right->3
In phần tử lớn nhất 1 = 10
lặp 2: Tham khảo heap ban đầu và chèn cả hai đó là trẻ em vào heap mới. (Lưu trữ các con trỏ cho họ và không phải là giá trị bản thân). Lý do bạn muốn lưu trữ con trỏ là để bạn có thể truy cập chúng trong O (1) từ heap ban đầu sau đó để tìm kiếm con của chúng thay vì O (N) để tìm kiếm nơi mà giá trị đó nằm trong heap gốc.
Bước 2a: Tìm con trái của nút gốc của vùng heap mới từ vùng gốc. Thêm một con trỏ cho con trái (trong trường hợp này là 5 ') vào heap mới.
10'
/
5'
New Heap, size = 2, root = 10', root->left = 5, root right->3
Bước 2b: Tìm con phải của nút gốc của heap mới từ vùng gốc. Thêm một con trỏ cho con trái (trong trường hợp này là 3 ') vào heap mới.
10'
/\
5' 3'
New Heap, size = 3, root = 10', root->left = 5, root right->3
Bước 2c: Xóa nút gốc khỏi Heap mới. (Swap nút max với đúng nhất rời, loại bỏ nút gốc và bong bóng xuống gốc hiện tại để duy trì sở hữu đống)
10' swap 3' remove & bubble 5'
/\ => /\ => /
5' 3' 5' 10' 3'
New Heap, size = 2, root = 5', root->left = 4, root right->1
In phần tử lớn nhất thứ 2 = 5
Bước 3a: Nhìn cho con trái của gốc nút của heap mới từ heap ban đầu. Thêm một con trỏ cho con trái (trong trường hợp này là 4 ') vào heap mới.
5'
/\
3' 4'
New Heap, size = 3, root = 5', root->left = 4, root right->1
Bước 3b: Tìm con phải của nút gốc của heap mới từ vùng gốc. Thêm con trỏ cho con bên trái (trong trường hợp này là 1 ') vào heap mới.
5'
/\
3' 4'
/
1'
New Heap, size = 4, root = 5', root->left = 4, root right->1
Bước 3c: Xóa nút gốc khỏi Heap mới. (Nút Swap max (5 ') New Heap với quyền của mình nhất khởi hành từ đống gốc (1') từ Heap mới, loại bỏ nút gốc và bong bóng xuống gốc hiện tại để duy trì sở hữu đống)
5' Swap 1' remove & bubble 4'
/\ => /\ => /\
3' 4' 3' 4' 3' 1'
/ /
1' 5'
New Heap, size = 3, root = 4', root->left = NULL, root right->NULL
In phần tử lớn thứ 3 = 4
Bước 4a & Bước 4b không làm gì vì nút gốc không có bất kỳ trẻ nào trong trường hợp này từ vùng gốc.
Bước 4c: Xóa nút gốc khỏi Heap mới. (nút max Swap với đúng nhất rời, loại bỏ nút gốc và bong bóng xuống gốc hiện tại để duy trì sở hữu đống ở New Heap)
4' Swap 1' remove & bubble 3'
/\ => /\ => /
3' 1' 3' 4' 1'
New Heap, size = 2, root = 3', root->left = 2, root right->0
In phần tử lớn nhất 4 = 3
Bước 5a: Tìm trái con của nút gốc của heap mới từ heap gốc. Thêm con trỏ cho con trái (trong trường hợp này là 2 ') vào heap mới.
3'
/\
1' 2'
New Heap, size = 3, root = 3', root->left = 2, root right->0
Bước 5b: Tìm con phải của nút gốc của heap mới từ vùng gốc. Thêm con trỏ cho con trái (trong trường hợp này là 0 ') vào heap mới.
3'
/\
1' 2'
/
0'
New Heap, size = 4, root = 3', root->left = 2, root right->0
Bước 5c: Xóa nút gốc khỏi Heap mới. (Hoán đổi nút tối đa (3 ') với phần lớn nhất của nó từ heap gốc (là 0') trong Heap Mới, loại bỏ nút gốc và bong bóng xuống gốc hiện tại để duy trì tài sản heap trong New Heap)
3' Swap 0' Remove & Bubble 2'
/\ => /\ => /\
1' 2' 1' 2' 1' 0'
/ /
0' 3'
New Heap, size = 3, root = 2', root->left = NULL, root->right = NULL
In phần tử lớn thứ 5 = 2
Cuối cùng, vì chúng ta đã trải qua k lần lặp, k = 5. Bây giờ chúng ta có thể trích xuất giá trị của phần tử gốc từ vùng mới. Trong trường hợp này, giá trị là 2. Do đó, chúng tôi đã tìm thấy giá trị lớn thứ k từ heap gốc.
Thời gian phức tạp, T (N, k) = O (klogk) Space phức tạp, S (N, k) = O (k)
Hope this helps!
Sớm Chee Loong,
Đại học Toronto.
có thể trùng lặp thuật toán thời gian [O (klogk) để tìm phần tử nhỏ nhất k từ một đống nhị phân] (http://stackoverflow.com/questions/7650917/oklogk-time-algorithm-to-find-kth-smallest- phần tử-từ-một-nhị phân-heap). Có thể không phải là một bản dupe, vì câu hỏi được liên kết yêu cầu phần tử thứ k chứ không phải là danh sách các phần tử lớn nhất thứ k, nhưng ý tưởng là như nhau. – amit