Có ai thực sự thực hiện một Fibonacci-Heap một cách hiệu quả?


151

Có ai trong số các bạn đã từng thực hiện một Fibonacci-Heap chưa? Tôi đã làm như vậy một vài năm trước, nhưng nó chậm hơn nhiều so với việc sử dụng BinHeaps dựa trên mảng.

Hồi đó, tôi nghĩ về nó như một bài học quý giá về cách nghiên cứu không phải lúc nào cũng tốt như nó tuyên bố. Tuy nhiên, rất nhiều tài liệu nghiên cứu khẳng định thời gian chạy của các thuật toán của họ dựa trên việc sử dụng Fibonacci-Heap.

Bạn đã bao giờ quản lý để tạo ra một thực hiện hiệu quả? Hay bạn đã làm việc với các tập dữ liệu lớn đến mức Fibonacci-Heap hiệu quả hơn? Nếu vậy, một số chi tiết sẽ được đánh giá cao.


25
Không phải bạn đã học được những anh chàng thuật toán này luôn che giấu các hằng số khổng lồ đằng sau cái lớn lớn của họ sao?! :) Có vẻ như trong thực tế, hầu hết thời gian, điều "n" đó thậm chí không bao giờ gần với "n0"!
Mehrdad Afshari

Tôi biết - bây giờ. Tôi đã triển khai nó khi lần đầu tiên nhận được bản sao "Giới thiệu về thuật toán". Ngoài ra, tôi đã không chọn Tarjan cho ai đó sẽ phát minh ra cấu trúc dữ liệu vô dụng, bởi vì Cây Splay của anh ta thực sự khá tuyệt.
mdm

mdm: Tất nhiên nó không vô dụng, nhưng cũng giống như kiểu sắp xếp chèn nhịp nhanh trong các tập dữ liệu nhỏ, các đống nhị phân có thể hoạt động tốt hơn do các hằng số nhỏ hơn.
Mehrdad Afshari

1
Trên thực tế, chương trình tôi cần rất nhiều cho việc tìm kiếm Steiner-Plants để định tuyến trong các chip VLSI, vì vậy các bộ dữ liệu không chính xác là nhỏ. Nhưng ngày nay (ngoại trừ những thứ đơn giản như sắp xếp) tôi sẽ luôn sử dụng thuật toán đơn giản hơn cho đến khi nó "phá vỡ" trên tập dữ liệu.
mdm

1
Câu trả lời của tôi cho điều này thực sự là "có". (Chà, đồng tác giả của tôi trên một tờ giấy đã làm.) Tôi không có mã ngay bây giờ, vì vậy tôi sẽ nhận được thêm thông tin trước khi tôi thực sự phản hồi. Tuy nhiên, nhìn vào biểu đồ của chúng tôi, tôi lưu ý rằng các đống F tạo ra sự so sánh ít hơn so với các đống b. Bạn đã sử dụng một cái gì đó mà so sánh là giá rẻ?
A. Rex

Câu trả lời:


136

Các thư viện Boost C ++ bao gồm việc triển khai các đống Fibonacci trong boost/pending/fibonacci_heap.hpp. Tập tin này rõ ràng đã tồn tại trong pending/nhiều năm và bởi những dự đoán của tôi sẽ không bao giờ được chấp nhận. Ngoài ra, đã có lỗi trong quá trình thực hiện, được sửa chữa bởi người quen của tôi và anh chàng lạnh lùng xung quanh Aaron Windsor. Thật không may, hầu hết các phiên bản của tệp mà tôi có thể tìm thấy trực tuyến (và phiên bản trong gói libboost-dev của Ubuntu) vẫn có lỗi; Tôi đã phải lấy một phiên bản sạch từ kho Subversion.

Kể từ phiên bản 1.49, các thư viện Boost C ++ đã thêm rất nhiều cấu trúc heaps mới bao gồm cả đống heap.

Tôi đã có thể biên dịch dijkstra_heap_performance.cpp dựa trên phiên bản sửa đổi của dijkstra_shortest_paths.hpp để so sánh các heap Fibros và heap nhị phân. (Trong dòng typedef relaxed_heap<Vertex, IndirectCmp, IndexMap> MutableQueue, thay đổi relaxedthành fibonacci.) Trước tiên tôi quên biên dịch với các tối ưu hóa, trong trường hợp đó, các heap nhị phân và nhị phân thực hiện như nhau, với các heap Fibros thường vượt trội hơn một lượng không đáng kể. Sau khi tôi biên dịch với tối ưu hóa rất mạnh, các đống nhị phân đã có một sự thúc đẩy to lớn. Trong các thử nghiệm của tôi, các heap Fibros chỉ vượt trội so với heap nhị phân khi đồ thị cực kỳ lớn và dày đặc, ví dụ:

Generating graph...10000 vertices, 20000000 edges.
Running Dijkstra's with binary heap...1.46 seconds.
Running Dijkstra's with Fibonacci heap...1.31 seconds.
Speedup = 1.1145.

Theo như tôi hiểu, điều này chạm đến sự khác biệt cơ bản giữa các đống Fibonacci và đống nhị phân. Sự khác biệt lý thuyết thực sự duy nhất giữa hai cấu trúc dữ liệu là các heap Fibros hỗ trợ khóa giảm trong thời gian không đổi (khấu hao). Mặt khác, các đống nhị phân có được rất nhiều hiệu suất từ ​​việc thực hiện như một mảng; sử dụng một cấu trúc con trỏ rõ ràng có nghĩa là các đống Fibonacci phải chịu một hiệu suất rất lớn.

Do đó, để hưởng lợi từ các đống Fibonacci trong thực tế , bạn phải sử dụng chúng trong một ứng dụng trong đó giảm_key là cực kỳ thường xuyên. Về mặt Dijkstra, điều này có nghĩa là đồ thị cơ bản dày đặc. Một số ứng dụng về bản chất có thể giảm_key-cường độ cao; Tôi muốn thử thuật toán cắt tối thiểu Nagomochi-Ibaraki vì rõ ràng nó tạo ra rất nhiều hàm giảm, nhưng quá nhiều nỗ lực để làm cho một phép so sánh thời gian hoạt động.

Cảnh báo : Tôi có thể đã làm điều gì đó sai. Bạn có thể muốn thử tái tạo những kết quả này cho mình.

Lưu ý về mặt lý thuyết : Hiệu suất được cải thiện của các đống Fibonacci trên less_key rất quan trọng đối với các ứng dụng lý thuyết, chẳng hạn như thời gian chạy của Dijkstra. Các đống Fibonacci cũng vượt trội so với các đống nhị phân khi chèn và sáp nhập (cả hai đều được khấu hao theo thời gian không đổi cho các đống Fibonacci). Việc chèn về cơ bản là không liên quan, vì nó không ảnh hưởng đến thời gian chạy của Dijkstra và việc sửa đổi các đống nhị phân cũng khá dễ dàng để chèn vào thời gian không đổi. Hợp nhất trong thời gian liên tục là tuyệt vời, nhưng không liên quan đến ứng dụng này.

Lưu ý cá nhân : Một người bạn của tôi và tôi đã từng viết một bài báo giải thích về hàng đợi ưu tiên mới, cố gắng sao chép thời gian chạy (lý thuyết) của đống Fibonacci mà không phức tạp. Bài báo chưa bao giờ được xuất bản, nhưng đồng tác giả của tôi đã thực hiện các đống nhị phân, các đống Fibonacci và hàng đợi ưu tiên của chúng ta để so sánh các cấu trúc dữ liệu. Các biểu đồ của các kết quả thử nghiệm chỉ ra rằng các heap nhị phân được thực hiện một chút so với các heap nhị phân được thực hiện một cách tổng thể so với tổng số so sánh, cho thấy các heap của Fibonacci sẽ hoạt động tốt hơn trong trường hợp chi phí so sánh vượt quá chi phí. Thật không may, tôi không có sẵn mã và có lẽ trong so sánh tình huống của bạn là rẻ, vì vậy những nhận xét này có liên quan nhưng không thể áp dụng trực tiếp.

Ngẫu nhiên, tôi đặc biệt khuyên bạn nên cố gắng khớp thời gian chạy của các đống Fibonacci với cấu trúc dữ liệu của riêng bạn. Tôi thấy rằng tôi chỉ đơn giản là phát minh lại đống Fibonacci. Trước đây tôi nghĩ rằng tất cả sự phức tạp của các đống Fibonacci là một số ý tưởng ngẫu nhiên, nhưng sau đó tôi nhận ra rằng tất cả chúng đều tự nhiên và khá gượng ép.


Cảm ơn! Câu hỏi này đã ngồi trong tâm trí tôi trong một thời gian dài. Tôi thực sự đã triển khai Dijkstra bằng cách sử dụng Fibonacci-Heaps trước khi tôi thử Steiner-Plants. Tuy nhiên, có vẻ như đồ thị của tôi nơi dày đặc hơn nhiều so với trong ví dụ của bạn. Họ có hàng triệu nút, nhưng mức độ trung bình chỉ 5-6.
mdm

Hiệu suất Fib Heap có thể dự đoán được thông qua chuỗi các hoạt động. Tôi đã viết một thuật toán Heap-heavy kết thúc nhanh hơn với Fib Heap (so với Bin Heap). Các mẹo đã được bó công việc. Bất kể tần suất của bất kỳ hoạt động nào, sự khác biệt nằm ở đây: DecreasKey - ExtractMin - DecreasKey - ExtractMin so với DecreasKey - DecreasKey - ExtractMin - ExtractMin (tiếp theo bên dưới)
Gaminic

Cái sau sẽ nhanh gấp đôi, vì ExtractMin thứ 2 gần như miễn phí. Thuật toán của chúng tôi trích xuất một loạt các phần tử Min trong đó nhiều phần tử bị loại bỏ; lãng phí cho Heap Bin, nhưng tốt hơn trên Heap Fib. Đáng buồn thay, điều này không được phản ánh rõ ràng trong thời gian phức tạp mà mọi người cung cấp khi nói về các thuật toán dựa trên Heap. Với giới hạn khấu hao, tổng độ phức tạp không chỉ đơn giản là # hoạt động * độ phức tạp của hoạt động.
Gaminic

1
Bất kỳ cơ hội nào cũng cố gắng ghép các đống và / hoặc đống thoải mái?
Thomas Ahle

1
Tôi không chắc tại sao kết quả của bạn lại xuất hiện quá gần, tôi đã sử dụng STL Prior_queue vs heap Tự thực hiện và đống heap nhị phân đứng sau một biên độ lớn trong các thử nghiệm của tôi .
Nicholas Pipitone

33

Knuth đã làm một so sánh giữa đống heap và đống nhị phân cho các cây kéo dài tối thiểu vào năm 1993 cho cuốn sách Stanford Graphbase của ông . Anh ta tìm thấy MySpace chậm hơn 30 đến 60 so với đống nhị phân ở các kích thước đồ thị mà anh ta đang thử nghiệm, 128 đỉnh ở các mật độ khác nhau.

Các mã nguồn là trong C (hay đúng hơn là CWEB đó là sự pha trộn giữa C, toán và TeX) trong phần MILES_SPAN.


1

Khước từ

Tôi biết kết quả khá giống nhau và "có vẻ như thời gian chạy hoàn toàn bị chi phối bởi một thứ khác ngoài đống" (@Alpedar). Nhưng tôi không thể tìm thấy bất cứ bằng chứng nào về điều đó trong mã. Mã được mở, vì vậy nếu bạn có thể tìm thấy bất cứ điều gì có thể ảnh hưởng đến kết quả của bài kiểm tra, xin vui lòng cho tôi biết.


Có thể tôi đã làm gì đó sai, nhưng tôi đã viết một bài kiểm tra , dựa trên A.Rex anwser so sánh:

  • Fibre-Heap
  • D-Ary-heap (4)
  • Nhị phân-Heap
  • Thư giãn-Heap

Thời gian thực hiện (chỉ dành cho đồ thị hoàn chỉnh) cho tất cả các đống rất gần nhau. Thử nghiệm đã được thực hiện cho các đồ thị hoàn chỉnh với 1000,2000,3000,4000,5000,6000,7000 và 8000 đỉnh. Đối với mỗi thử nghiệm, 50 biểu đồ ngẫu nhiên đã được tạo và đầu ra là thời gian trung bình của mỗi heap:

Xin lỗi về đầu ra, nó không dài dòng vì tôi cần nó để xây dựng một số biểu đồ từ các tệp văn bản.


Đây là kết quả (tính bằng giây):

bảng kết quả heap


4
Có bao nhiêu cạnh trong mỗi trường hợp? Và thuật toán nào bạn đang chạy chính xác? Kết quả của bạn sẽ không có ý nghĩa nếu chúng ta không biết những gì chúng ta đang giải quyết.
kokx

Khi tôi buồn, tất cả các đồ thị đã hoàn thành, vì vậy bạn có thể tính toán số cạnh cho mỗi trường hợp. Ý bạn là gì, "bạn đang chạy chính xác". Họ đang ở trong đầu của các bảng.
Guilherme Torres Castro

22
Điều này có vẻ như thời gian chạy hoàn toàn bị chi phối bởi một thứ khác ngoài heap (nó có thể tạo ra biểu đồ hoặc một số IO). Những kết quả gần như chính xác là không thể tin được.
Alpedar

2
Có lẽ thời gian os bị chi phối bởi một thứ khác, nhưng tôi chắc chắn đó không phải là IO hoặc việc tạo ra các biểu đồ. Dù sao, mã nguồn có sẵn và tôi sẽ rất vui mừng nếu ai đó tìm thấy một lỗi và sửa lỗi.
Guilherme Torres Castro

Những bài kiểm tra dường như đang đo lường một cái gì đó hoàn toàn khác nhau. Bạn có thể nhận xét về bài kiểm tra bạn đã chạy? Hãy nhớ rằng Bài toán đường đi ngắn nhất trên đồ thị hoàn chỉnh là O (1) nếu khoảng cách là Hình học / Euclidian.
Gaminic

0

Tôi cũng đã làm một thí nghiệm nhỏ với đống Fibonacci. Đây là liên kết để biết chi tiết: Experimenting-with-dijkstras-Thuật toán . Tôi vừa googled các thuật ngữ "Fibros heap java" và đã thử một vài triển khai mã nguồn mở hiện tại của heap Fibonacci. Có vẻ như một số trong số họ có một số vấn đề hiệu suất, nhưng có một số đó là khá tốt. Ít nhất, họ đang đánh bại hiệu suất PQ ngây thơ và nhị phân trong bài kiểm tra của tôi. Có lẽ họ có thể giúp thực hiện một cách hiệu quả.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.