Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement heapify in HeapPriorityQueue.addAll #732

Open
aamirki opened this issue Dec 14, 2024 · 1 comment · May be fixed by #734
Open

Implement heapify in HeapPriorityQueue.addAll #732

aamirki opened this issue Dec 14, 2024 · 1 comment · May be fixed by #734

Comments

@aamirki
Copy link

aamirki commented Dec 14, 2024

Current HeapPriorityQueue calls add for each element in the given Iterable yielding a time complexity of $O(n * logn)$, but if the heapify algorithm is used instead the time complexity can be reduced to $O(n)$. This has been done in other languages such as Go for example: https://cs.opensource.google/go/go/+/refs/tags/go1.23.4:src/container/heap/heap.go;l=41

@lrhn
Copy link
Member

lrhn commented Dec 16, 2024

The "heapify" algorithm has linear performance for creating a heap from an existing list.
It won't work directly for addAll if the heap isn't empty.
It can add all the new elements to the end of the heap, and then run the heapify algorithm on the entire heap. That may not be faster than just bubbling up the new elements, but that depends on the number of elements added.
I don't know if it's meaningful to adapt the algorithm to knowing that some elements are already heap-ordered. Probably too expensive, the complexity of heapify is very low.

We should have the heapify algorithm, could add a .of constructor to initialize with it, and maybe use it for addAll if it's expected to be faster than just saying each new element independently.

Adding M elements individually to a heap of size N has time O(M×log(M+N)), adding and heapifying has time O(M+N). The latter is better if log2(M+N) > (M+N)/M. A doubling or more (N<=M) will always satisfy that for non trivial sizes (N >= 2). Less may also be OK, but then we should probably consider the constant factor too. If we less than double, we can probably approximate N+M with just N, so it's log2(N) > N/M, or M > N/log2(N).

Or even more approximate and in Dart, m * n.bitCount > n. That seems efficient enough to use as a test for whether to bubble all the new elements up, or heapify the entire heap.

LGTM.

@lrhn lrhn linked a pull request Dec 18, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants