2010-10-20 29 views
13

Tôi đang xem triển khai hàng đợi ưu tiên với yêu cầu bổ sung, chức năng tìm/tìm kiếm sẽ cho biết một mục có ở bất kỳ đâu trong hàng đợi hay không. Vì vậy, các chức năng sẽ là: chèn, del-min và tìm.Hàng đợi ưu tiên với chức năng tìm kiếm - Triển khai nhanh nhất

Tôi không chắc mình nên sử dụng cây tìm kiếm nhị phân Heap hoặc tự cân bằng. Nó xuất hiện PQs thường được thực hiện với một Heap, nhưng tôi tự hỏi nếu có bất kỳ lợi thế trong việc sử dụng một cây tìm kiếm nhị phân vì tôi cũng cần có chức năng tìm.

Hơn nữa, trung bình tôi sẽ thực hiện nhiều lần chèn hơn xóa. Tôi cũng đang xem xét d-ary heap. Về cơ bản, mỗi giây đều được tính.

Cảm ơn!

+0

"trung bình tôi sẽ thực hiện nhiều lần chèn hơn xóa" - đó là _really_ ý của bạn là gì? Nếu đó là trường hợp, cuối cùng bạn sẽ hết bộ nhớ, phải không? – paxdiablo

+2

hàng đợi ưu tiên dành cho thuật toán tìm đường dẫn. khi tôi đạt được mục tiêu của mình, tôi chỉ có thể xóa phần còn lại của hàng đợi ưu tiên mà không cần phải cân bằng lại. – Harry

+1

@paxdiablo - cách vòng khác chỉ đơn giản là không thể ... không phải mọi chương trình đều chạy dài – tobyodavies

Trả lời

0

Tìm kiếm IIRC/tìm trên heap là O(n) trong khi trên cây là O(log(n)) và các hoạt động PQ chuẩn khác giống nhau.

Heaps chỉ thực sự hiệu quả hơn bởi một số yếu tố không đổi, do đó nếu hàng đợi lớn thì cây sẽ tốt hơn, nếu nhỏ của nó, bạn cần kiểm tra và cấu hình. tất cả những điều tốt đẹp để biết về lý thuyết đều nhanh hơn, nhưng nếu những yếu tố không đổi đó lớn thì có thể hoàn toàn không liên quan đến các tập dữ liệu đủ nhỏ.

+1

Tôi đã bình chọn câu trả lời này vì nó sai. Heaps và cây tìm kiếm có các hoạt động thực sự khác nhau được hỗ trợ và độ phức tạp khác nhau. 'find-min' trong một heap là' O (1) 'trong khi trong cây tìm kiếm cân bằng, nó là' O (log n) '. Chèn vào một số heaps là 'O (1)', trong cây tìm kiếm nó là 'O (log n)'. Và nó không chỉ là lý thuyết. Những phức hợp 'O (log n)' so với 'O (1)' có thể có hiệu suất rất lớn. – Celelibi

4

Tại sao bạn không thể sử dụng Hàng đợi ưu tiên và Tập hợp? Khi bạn enqueue một cái gì đó, bạn thêm nó vào bộ này. Khi bạn dequeue nó, bạn loại bỏ nó từ bộ này. Bằng cách đó, bộ sẽ cho bạn biết nếu có gì đó trong hàng đợi.

4

Nếu hoạt động tìm kiếm của bạn tương đối không thường xuyên (và vùng heap của bạn khá nhỏ), tôi chỉ thực hiện tìm kiếm tuyến tính. Nếu nó là tương đối thường xuyên, hoặc đống là rất lớn, hãy xem xét theo dõi thành viên heap (để làm 'tìm' kiểm tra của bạn) với một cấu trúc dữ liệu riêng biệt hoặc một lá cờ đối tượng. Niềm vui của việc lập chỉ mục bên ngoài là có thể đưa đối tượng của bạn vào bao nhiêu vùng chứa tùy thích.

Nếu bằng cách 'tìm' bạn thực sự có nghĩa là 'tìm và sửa đổi' (tôi thấy tôi thường cần xóa mọi thứ khỏi hàng đợi ưu tiên độc lập với insert/del-min), đây là ba phương pháp tôi đã sử dụng:

Với tỷ lệ chèn/del-min cao (100k/s liên tục) và tỷ lệ tìm kiếm xóa thấp (nói 1/s) trên một nhóm làm việc khá nhỏ (500-1000), tôi đã thực hiện tìm kiếm tuyến tính cho phần tử và sau đó xóa nó khỏi cây theo cách tiêu chuẩn.

Với tỷ lệ chèn/del-min cao cộng với tìm kiếm xóa thường xuyên, tôi chỉ đơn giản là đánh dấu các đối tượng đã xóa là "không quan tâm" sau khi tìm chúng gián tiếp. Việc miễn phí thực tế đã được hoãn lại cho đến khi đối tượng được dequeued như bình thường.

Cho một tiêu chuẩn nhỏ :: priority_queue (không có phương thức truy cập bên ngoài chèn/del-min) chỉ một vài yếu tố và xóa thường xuyên, tôi vừa sao chép toàn bộ hàng đợi vào một std :: vector và sao chép tạm thời phần được sửa đổi/mong muốn trở lại hàng đợi. Sau đó tôi đã khóc khi ngủ.

+0

Cờ "không thú vị" có thể là một cuộc sống tiết kiệm cho tôi. –

-1

Lưu trữ dữ liệu của bạn trong vùng chứa nhanh nhất mà bạn đã thử nghiệm và sử dụng bộ lọc nở để kiểm tra xem có gì trong vùng chứa hay không.

Tôi đã phối hợp bộ lọc nở hoa với bảng băm trong dự án trước và nó tăng tốc 400 lần trên bảng băm với trung bình khoảng 10 nghìn mục.

Bộ lọc nở có một vài đặc tính thú vị:

  • Nếu câu trả lời là không từ một bộ lọc nở, đó là 100% đáng tin cậy.
  • Nếu câu trả lời là có, bạn phải kiểm tra các dữ liệu khác cấu trúc để đảm bảo mục đó thực sự có mặt.
  • Hãy chắc chắn rằng bạn chọn một hàm băm tốt :)
+0

Bạn không thể xóa phần tử khỏi bộ lọc nở, vì vậy khi bạn bật(), bộ lọc nở sẽ _always_ hiển thị phần tử ở đó. Cuối cùng, bộ lọc nở sẽ _always_ hiển thị _anything_ là ở đó. –

2

Nếu bạn cần những lợi ích của nhiều hơn một cấu trúc dữ liệu thì bạn có thể sử dụng chúng trong phần. Ví dụ: Ví dụ: nếu bạn cần lợi ích của hàng đợi ưu tiên và cây tìm kiếm nhị phân thì hãy thực hiện các hành động bạn muốn trên cả hai.

Nếu đó là insert thì hãy chèn phần tử vào cả hai.

Nếu đó là find thì bạn có thể tìm phần tử bằng cách sử dụng cây tìm kiếm nhị phân và nếu tìm thấy nó sau đó tiếp tục tìm phần tử đó trong hàng đợi ưu tiên.

Nếu đó là min thì hãy xóa nó trước tiên khỏi hàng đợi ưu tiên và bây giờ bạn biết được phần tử nào thì bạn có thể xóa phần tử đó khỏi cây tìm kiếm nhị phân.

nếu đó là del thì trước tiên hãy tìm nó trong cây tìm kiếm nhị phân và xóa nó sau đó tiếp tục tìm nó trong hàng đợi ưu tiên và xóa nó khỏi đó.

Giả sử rằng các nút của cây nhị phân và các nút của hàng đợi ưu tiên là các con trỏ tới các phần tử của bạn.

0

Radix trees với thuộc tính min-heap sẽ cung cấp các thuộc tính bạn cần. Điều này thực sự sẽ cung cấp cho bạn sự phức tạp về thời gian liên tục cho các hoạt động của bạn. Ví dụ: nếu chúng ta xem this Haskell implementation, tất cả ba hoạt động bạn đề cập đều có độ phức tạp thời gian O (min (n, W)). Trong đó n là số phần tử và W là số bit trong một int (32 hoặc 64).