Sự khác biệt giữa một đống và BST là gì?
Khi nào nên sử dụng một đống và khi nào sử dụng BST?
Nếu bạn muốn có được các yếu tố theo cách sắp xếp, BST có tốt hơn heap không?
Sự khác biệt giữa một đống và BST là gì?
Khi nào nên sử dụng một đống và khi nào sử dụng BST?
Nếu bạn muốn có được các yếu tố theo cách sắp xếp, BST có tốt hơn heap không?
Câu trả lời:
Tóm lược
Type BST (*) Heap
Insert average log(n) 1
Insert worst log(n) log(n) or n (***)
Find any worst log(n) n
Find max worst 1 (**) 1
Create worst n log(n) n
Delete worst log(n) log(n)
Tất cả thời gian trung bình trên bảng này giống như thời gian tồi tệ nhất của chúng ngoại trừ Chèn.
*
: ở mọi nơi trong câu trả lời này, BST == BST cân bằng, vì không cân bằng hút không có triệu chứng**
: sử dụng một sửa đổi tầm thường được giải thích trong câu trả lời này***
: log(n)
cho heap cây con trỏ, n
cho heap mảng độngƯu điểm của đống nhị phân so với BST
thời gian trung bình chèn vào một đống nhị phân là O(1)
, đối với BST là O(log(n))
. Đây là tính năng sát thủ của đống.
Ngoài ra còn có các đống khác đạt được O(1)
khấu hao (mạnh hơn) như Heap Fibros , và thậm chí trường hợp xấu nhất, như hàng đợi Brodal , mặc dù chúng có thể không thực tế vì hiệu suất không có triệu chứng: Các đống Fibonacci hoặc hàng đợi Brodal được sử dụng trong thực tế ở bất cứ đâu?
đống nhị phân có thể được thực hiện một cách hiệu quả trên đỉnh của các mảng động hoặc cây dựa trên con trỏ, cây chỉ dựa trên BST. Vì vậy, đối với heap, chúng ta có thể chọn triển khai mảng hiệu quả hơn về không gian, nếu chúng ta có thể đủ khả năng thay đổi kích thước thời gian trễ.
tạo heap nhị phân là O(n)
trường hợp xấu nhất , O(n log(n))
đối với BST.
Lợi thế của BST so với đống nhị phân
tìm kiếm các yếu tố tùy ý là O(log(n))
. Đây là tính năng sát thủ của BST.
Đối với heap, nó O(n)
nói chung, ngoại trừ phần tử lớn nhất O(1)
.
Lợi thế "sai" của heap so với BST
Heap là O(1)
để tìm max, BST O(log(n))
.
Đây là một quan niệm sai lầm phổ biến, bởi vì việc sửa đổi BST để theo dõi phần tử lớn nhất và cập nhật nó bất cứ khi nào phần tử đó có thể thay đổi: khi chèn một hoán đổi lớn hơn, khi loại bỏ tìm phần lớn thứ hai. Chúng ta có thể sử dụng cây tìm kiếm nhị phân để mô phỏng hoạt động heap không? (được đề cập bởi Yeo ).
Trên thực tế, đây là một hạn chế của đống so với các BST: tìm kiếm hiệu quả duy nhất là cho phần tử lớn nhất.
Chèn heap nhị phân trung bình là O(1)
Nguồn:
Lập luận trực quan:
Trong một đống nhị phân, tăng giá trị tại một chỉ mục nhất định cũng O(1)
vì lý do tương tự. Nhưng nếu bạn muốn làm điều đó, có khả năng bạn sẽ muốn cập nhật một chỉ mục bổ sung cho các hoạt động heap Làm thế nào để thực hiện thao tác giảm phím O (logn) cho Hàng đợi ưu tiên dựa trên heap? ví dụ cho Dijkstra. Có thể không có chi phí thêm thời gian.
Thư viện chuẩn GCC C ++ chèn điểm chuẩn trên phần cứng thực
Tôi đã điểm chuẩn C ++ std::set
( BST cây đen đỏ ) và chèn std::priority_queue
( heap mảng động ) để xem liệu tôi có đúng về thời gian chèn hay không và đây là những gì tôi nhận được:
Vì vậy, rõ ràng:
thời gian chèn heap về cơ bản là không đổi.
Chúng ta có thể thấy rõ các điểm thay đổi kích thước mảng động. Vì chúng tôi đang tính trung bình cứ sau 10k chèn để có thể nhìn thấy mọi thứ ở mức nhiễu trên hệ thống , nên các đỉnh đó thực tế lớn hơn khoảng 10 nghìn lần so với hiển thị!
Biểu đồ thu phóng loại trừ về cơ bản chỉ các điểm thay đổi kích thước mảng và cho thấy hầu hết tất cả các phần chèn đều nằm dưới 25 nano giây.
BST là logarit. Tất cả các chèn đều chậm hơn nhiều so với chèn heap trung bình.
Phân tích chi tiết BST vs hashmap tại: Cấu trúc dữ liệu nào bên trong std :: map trong C ++?
Thư viện chuẩn GCC C ++ chèn điểm chuẩn trên gem5
gem5 là một trình giả lập hệ thống đầy đủ, và do đó cung cấp một đồng hồ chính xác vô cùng với m5 dumpstats
. Vì vậy, tôi đã cố gắng sử dụng nó để ước tính thời gian cho các lần chèn riêng lẻ.
Diễn dịch:
Heap vẫn không đổi, nhưng bây giờ chúng ta thấy chi tiết hơn rằng có một vài dòng, và mỗi dòng cao hơn thì thưa thớt hơn.
Điều này phải tương ứng với độ trễ truy cập bộ nhớ được thực hiện cho các chèn cao hơn và cao hơn.
TODO Tôi thực sự không thể diễn giải BST đầy đủ vì nó trông không quá logarit và có phần bất biến hơn.
Tuy nhiên, với chi tiết lớn hơn này, chúng ta có thể thấy cũng có thể thấy một vài dòng riêng biệt, nhưng tôi không chắc chúng đại diện cho cái gì: Tôi có thể mong đợi dòng dưới cùng mỏng hơn, vì chúng ta chèn dưới cùng?
Điểm chuẩn với thiết lập Buildroot này trên CPU aarch64 HPI .
BST không thể được thực hiện hiệu quả trên một mảng
Hoạt động heap chỉ cần bong bóng lên hoặc xuống một nhánh cây, vì vậy O(log(n))
trường hợp xấu nhất là hoán đổi, O(1)
trung bình.
Giữ BST cân bằng đòi hỏi phải xoay cây, có thể thay đổi phần tử trên cùng cho phần tử khác và sẽ yêu cầu di chuyển toàn bộ mảng xung quanh ( O(n)
).
Heaps có thể được thực hiện hiệu quả trên một mảng
Chỉ số phụ huynh và trẻ em có thể được tính toán từ chỉ số hiện tại như được hiển thị ở đây .
Không có hoạt động cân bằng như BST.
Xóa min là thao tác đáng lo ngại nhất vì nó phải từ trên xuống. Nhưng nó luôn có thể được thực hiện bằng cách "tô màu xuống" một nhánh của đống như được giải thích ở đây . Điều này dẫn đến trường hợp xấu nhất O (log (n)), vì heap luôn được cân bằng tốt.
Nếu bạn đang chèn một nút duy nhất cho mỗi nút bạn xóa, thì bạn sẽ mất lợi thế của chèn trung bình O (1) không có triệu chứng mà heaps cung cấp khi việc xóa sẽ chiếm ưu thế và bạn cũng có thể sử dụng BST. Tuy nhiên, Dijkstra cập nhật các nút nhiều lần cho mỗi lần xóa, vì vậy chúng tôi vẫn ổn.
Heap mảng động so với đống cây con trỏ
Heaps có thể được thực hiện một cách hiệu quả trên đỉnh heap con trỏ: Có thể thực hiện heap nhị phân dựa trên con trỏ hiệu quả không?
Việc thực hiện mảng động là không gian hiệu quả hơn. Giả sử rằng mỗi phần tử heap chỉ chứa một con trỏ tới struct
:
việc thực hiện cây phải lưu trữ ba con trỏ cho mỗi phần tử: cha mẹ, con trái và con phải. Vì vậy, việc sử dụng bộ nhớ luôn luôn 4n
(3 con trỏ cây + 1 struct
con trỏ).
Các BST cây cũng sẽ cần thêm thông tin cân bằng, ví dụ như màu đen-đỏ.
việc thực hiện mảng động có thể có kích thước 2n
chỉ sau khi nhân đôi. Vì vậy, trung bình nó sẽ được 1.5n
.
Mặt khác, heap cây có chèn trường hợp xấu nhất tốt hơn, bởi vì sao chép mảng động sao lưu để tăng gấp đôi kích thước của nó thì O(n)
trường hợp xấu nhất, trong khi đó, heap cây chỉ thực hiện phân bổ nhỏ mới cho mỗi nút.
Tuy nhiên, nhân đôi mảng sao lưu được O(1)
khấu hao, do đó, nó được xem xét đến độ trễ tối đa. Đề cập ở đây .
Triết học
Các BST duy trì một tài sản toàn cầu giữa cha mẹ và tất cả con cháu (trái nhỏ hơn, phải lớn hơn).
Nút trên cùng của BST là phần tử ở giữa, đòi hỏi kiến thức toàn cầu để duy trì (biết có bao nhiêu phần tử nhỏ hơn và lớn hơn).
Tài sản toàn cầu này đắt hơn để duy trì (log n insert), nhưng cung cấp các tìm kiếm mạnh mẽ hơn (tìm kiếm log n).
Heaps duy trì một tài sản địa phương giữa cha mẹ và con cái trực tiếp (cha mẹ> con cái).
Nút trên cùng của một đống là phần tử lớn, chỉ yêu cầu kiến thức địa phương để duy trì (biết cha mẹ của bạn).
So sánh BST vs Heap vs Hashmap:
BST: có thể là hợp lý:
heap: chỉ là một máy phân loại. Không thể là một tập hợp không có thứ tự hiệu quả, bởi vì bạn chỉ có thể kiểm tra nhanh phần tử nhỏ nhất / lớn nhất.
bản đồ băm: chỉ có thể là một tập hợp không có thứ tự, không phải là một máy sắp xếp hiệu quả, bởi vì băm trộn lẫn bất kỳ thứ tự nào.
Danh sách liên kết đôi
Một danh sách liên kết đôi có thể được xem là tập hợp con của heap trong đó mục đầu tiên có mức độ ưu tiên cao nhất, vì vậy hãy so sánh chúng ở đây:
O(1)
trường hợp xấu nhất vì chúng tôi có con trỏ tới các mục và việc cập nhật thực sự đơn giảnO(1)
trung bình, do đó tồi tệ hơn danh sách liên kết. Đánh đổi để có vị trí chèn chung hơn.O(n)
cho cả haiMột trường hợp sử dụng cho điều này là khi khóa của heap là dấu thời gian hiện tại: trong trường hợp đó, các mục mới sẽ luôn đi đến đầu danh sách. Vì vậy, chúng ta thậm chí có thể quên hoàn toàn dấu thời gian chính xác và chỉ giữ vị trí trong danh sách là ưu tiên.
Điều này có thể được sử dụng để thực hiện bộ đệm LRU . Giống như đối với các ứng dụng heap như Dijkstra , bạn sẽ muốn giữ một hashmap bổ sung từ khóa đến nút tương ứng của danh sách, để tìm nút nào cần cập nhật nhanh chóng.
So sánh các BST cân bằng khác nhau
Mặc dù thời gian chèn và tìm tiệm cận cho tất cả các cấu trúc dữ liệu thường được phân loại là "BST cân bằng" mà tôi đã thấy cho đến nay là như nhau, các BBST khác nhau có sự đánh đổi khác nhau. Tôi chưa nghiên cứu đầy đủ về vấn đề này, nhưng sẽ rất tốt nếu tóm tắt những sự đánh đổi này ở đây:
Xem thêm
Câu hỏi tương tự trên CS: /cs/27860/whats-the-difference-b between-a-binary-search-tree-and-a- binary-heap
Heap chỉ đảm bảo rằng các phần tử ở mức cao hơn lớn hơn (đối với heap tối đa) hoặc nhỏ hơn (đối với heap tối thiểu) so với các phần tử ở mức thấp hơn, trong khi BST đảm bảo thứ tự (từ "trái" sang "phải"). Nếu bạn muốn các yếu tố được sắp xếp, đi với BST.
[1, 5, 9, 7, 15, 10, 11]
đại diện cho một heap min hợp lệ, nhưng 7
ở mức 3 nhỏ hơn 9
ở cấp 2. Để trực quan hóa, hãy xem ví dụ 25
và 19
các phần tử trong hình ảnh Wikipedia mẫu cho heap . (Cũng lưu ý rằng mối quan hệ bất bình đẳng giữa các yếu tố không nghiêm ngặt, vì các yếu tố không nhất thiết phải là duy nhất.)
Khi nào nên sử dụng một đống và khi nào sử dụng BST
Heap tốt hơn ở findMin / findMax ( O(1)
), trong khi BST tốt ở tất cả find ( O(logN)
). Chèn là O(logN)
cho cả hai cấu trúc. Nếu bạn chỉ quan tâm đến findMin / findMax (ví dụ: liên quan đến ưu tiên), hãy đi với heap. Nếu bạn muốn mọi thứ được sắp xếp, hãy đi với BST.
Một vài slide đầu tiên từ đây giải thích mọi thứ rất rõ ràng.
Như đã đề cập bởi những người khác, Heap có thể làm findMin
hoặc findMax
trong O (1) nhưng không phải cả hai trong cùng một cấu trúc dữ liệu. Tuy nhiên tôi không đồng ý rằng Heap tốt hơn trong findMin / findMax. Trong thực tế, với một sửa đổi nhỏ, BST có thể thực hiện cả hai findMin
và findMax
trong O (1).
Trong BST được sửa đổi này, bạn theo dõi nút tối thiểu và nút tối đa mỗi khi bạn thực hiện một thao tác có khả năng sửa đổi cấu trúc dữ liệu. Ví dụ: trong thao tác chèn, bạn có thể kiểm tra xem giá trị min có lớn hơn giá trị mới chèn không, sau đó gán giá trị min cho nút mới được thêm vào. Kỹ thuật tương tự có thể được áp dụng trên giá trị tối đa. Do đó, BST này chứa những thông tin mà bạn có thể truy xuất chúng trong O (1). (giống như đống nhị phân)
Trong BST này (BST cân bằng), khi bạn pop min
hoặc pop max
, giá trị min tiếp theo được gán là sự kế thừa của nút min, trong khi giá trị tối đa tiếp theo được gán là tiền thân của nút max. Do đó, nó thực hiện trong O (1). Tuy nhiên, chúng ta cần phải cân bằng lại cây, do đó nó sẽ vẫn chạy O (log n). (giống như đống nhị phân)
Tôi sẽ được quan tâm để nghe suy nghĩ của bạn trong bình luận dưới đây. Cảm ơn :)
Tham chiếu chéo cho câu hỏi tương tự Chúng ta có thể sử dụng cây tìm kiếm nhị phân để mô phỏng hoạt động heap không? để thảo luận thêm về mô phỏng Heap bằng BST.
popMin
hoặc popMax
nó không phải là O (1), mà là O (log n) vì nó phải là BST cân bằng cần phải cân bằng lại mỗi thao tác xóa. Do đó, nó giống như heap nhị phân popMin
hoặc popMax
chạy O (log n)
Cây tìm kiếm nhị phân sử dụng định nghĩa: với mỗi nút, nút bên trái của nó có giá trị (khóa) ít hơn và nút ở bên phải của nó có giá trị (khóa) lớn hơn.
Trong trường hợp heap, việc triển khai cây nhị phân sử dụng định nghĩa sau:
Nếu A và B là các nút, trong đó B là nút con của A, thì giá trị (khóa) của A phải lớn hơn hoặc bằng giá trị (khóa) của B.That là, khóa (A) (B) ).
http://wiki.answers.com/Q/Difference_b between_binary_search_tree_and_heap_tree
Tôi đã chạy trong cùng một câu hỏi ngày hôm nay cho kỳ thi của tôi và tôi đã làm đúng. nụ cười ... :)
Một cách sử dụng BST khác trên Heap; bởi vì một sự khác biệt quan trọng:
Sử dụng BST trên một đống : Bây giờ, hãy nói rằng chúng tôi sử dụng cấu trúc dữ liệu để lưu trữ thời gian hạ cánh của các chuyến bay. Chúng tôi không thể sắp xếp chuyến bay hạ cánh nếu chênh lệch thời gian hạ cánh nhỏ hơn 'd'. Và giả sử nhiều chuyến bay đã được lên kế hoạch hạ cánh trong cấu trúc dữ liệu (BST hoặc Heap).
Bây giờ, chúng tôi muốn sắp xếp một chuyến bay khác sẽ hạ cánh tại t . Do đó, chúng ta cần tính toán sự khác biệt của t với người kế nhiệm và người tiền nhiệm của nó (nên> d). Vì vậy, chúng ta sẽ cần một BST cho việc này, nó sẽ nhanh, tức là trong O (logn) nếu được cân bằng.
CHỈNH SỬA:
Sắp xếp BST mất thời gian O (n) để in các phần tử theo thứ tự được sắp xếp (Inorder traversal), trong khi Heap có thể làm điều đó trong thời gian O (n logn). Heap trích xuất phần tử min và sắp xếp lại mảng, điều này làm cho nó thực hiện sắp xếp theo thời gian O (n logn).
from unsorted to sorted sequence. O(n) time for inorder traversal of a BST, which gives sorted sequence.
Chà, từ trình tự chưa được sắp xếp đến BST Tôi không biết một phương pháp dựa trên so sánh khóa với thời gian ít hơn O (n logn), chi phối BST thành phần trình tự. (Trong khi đó có O (n) heap xây dựng.). Tôi coi điều đó là công bằng (nếu vô nghĩa) khi các đống trạng thái gần với sự không sắp xếp và các BST được sắp xếp.
Heap chỉ đảm bảo rằng các phần tử ở cấp cao hơn lớn hơn (đối với heap tối đa) hoặc nhỏ hơn (đối với heap tối thiểu) so với các phần tử ở cấp thấp hơn
Tôi thích câu trả lời trên và đưa nhận xét của tôi chỉ cụ thể hơn cho nhu cầu và cách sử dụng của tôi. Tôi phải lấy danh sách n vị trí tìm khoảng cách từ mỗi vị trí đến điểm cụ thể nói (0,0) và sau đó trả về các vị trí am có khoảng cách nhỏ hơn. Tôi đã sử dụng Hàng đợi ưu tiên là Heap. Để tìm khoảng cách và đưa vào heap, tôi phải mất n (log (n)) n-vị trí log (n) mỗi lần chèn. Sau đó, để có được m với khoảng cách ngắn nhất, phải mất m (log (n)) m-location log (n) xóa đi sự nóng lên.
Nếu tôi phải làm điều này với BST, nó sẽ khiến tôi phải chèn trường hợp xấu nhất. (Giả sử giá trị đầu tiên rất nhỏ và tất cả các giá trị khác kéo dài hơn và dài hơn và cây kéo dài sang phải con hoặc trái trong trường hợp nhỏ hơn và nhỏ hơn. Min sẽ mất thời gian O (1) nhưng một lần nữa tôi phải cân bằng. Vì vậy, từ tình huống của tôi và tất cả các câu trả lời trên tôi nhận được là khi bạn chỉ sau khi các giá trị ở mức tối thiểu hoặc tối đa cho đống.