Improve asymptotic performance of binary treemap #44
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The current algorithm for computing partitions in a binary treemap performs a lot of redundant prefix sums and therefore has sub-optimal asymptotic performance.
In the worst-case, where each call to
partition
results in the right split having exactly one child node (this happens when children have values in increasing powers of two), the runtime is O(n2). On the other hand, the best-case performance is O(n), when the values are in decreasing powers of two.The asymptotic performance can be improved by pre-computing the prefix sums of all the children and performing a binary search at each call to
partition
to locate the split point. With this, the best-case performance is O(n) (for even splits when all children have the same value) and the worst-case performance is O(n log n) (for unbalanced splits).Here are some results of a benchmark that measures execution times for 1,000 iterations of three trees with 1,000 children on my machine (Macbook Pro with Node v5.3.0).
Before:
After:
There is of course some overhead for creating the prefix sum array, but the performance is consistent across different value distributions. In particular, the worst-case has improved by almost 20X, while the best-case has degraded by less than 25%.
The fix currently uses an inline implementation of binary search, but Lines 22-30 can be replaced with the following if
d3-array
is included as a dependency: