diff options
| author | George Spelvin <[email protected]> | 2019-05-14 22:42:52 +0000 |
|---|---|---|
| committer | Linus Torvalds <[email protected]> | 2019-05-15 02:52:49 +0000 |
| commit | 22a241ccb2c19962a0fb02c98154aa93d3fc1862 (patch) | |
| tree | 7e904cf792f6cab5801216698205d5af5cf86211 /lib/bitmap.c | |
| parent | lib/sort: make swap functions more generic (diff) | |
| download | kernel-22a241ccb2c19962a0fb02c98154aa93d3fc1862.tar.gz kernel-22a241ccb2c19962a0fb02c98154aa93d3fc1862.zip | |
lib/sort: use more efficient bottom-up heapsort variant
This uses fewer comparisons than the previous code (approaching half as
many for large random inputs), but produces identical results; it
actually performs the exact same series of swap operations.
Specifically, it reduces the average number of compares from
2*n*log2(n) - 3*n + o(n)
to
n*log2(n) + 0.37*n + o(n).
This is still 1.63*n worse than glibc qsort() which manages n*log2(n) -
1.26*n, but at least the leading coefficient is correct.
Standard heapsort, when sifting down, performs two comparisons per
level: one to find the greater child, and a second to see if the current
node should be exchanged with that child.
Bottom-up heapsort observes that it's better to postpone the second
comparison and search for the leaf where -infinity would be sent to,
then search back *up* for the current node's destination.
Since sifting down usually proceeds to the leaf level (that's where half
the nodes are), this does O(1) second comparisons rather than log2(n).
That saves a lot of (expensive since Spectre) indirect function calls.
The one time it's worse than the previous code is if there are large
numbers of duplicate keys, when the top-down algorithm is O(n) and
bottom-up is O(n log n). For distinct keys, it's provably always
better, doing 1.5*n*log2(n) + O(n) in the worst case.
(The code is not significantly more complex. This patch also merges the
heap-building and -extracting sift-down loops, resulting in a net code
size savings.)
x86-64 code size 885 -> 767 bytes (-118)
(I see the checkpatch complaint about "else if (n -= size)". The
alternative is significantly uglier.)
Link: http://lkml.kernel.org/r/2de8348635a1a421a72620677898c7fd5bd4b19d.1552704200.git.lkml@sdf.org
Signed-off-by: George Spelvin <[email protected]>
Acked-by: Andrey Abramov <[email protected]>
Acked-by: Rasmus Villemoes <[email protected]>
Reviewed-by: Andy Shevchenko <[email protected]>
Cc: Daniel Wagner <[email protected]>
Cc: Dave Chinner <[email protected]>
Cc: Don Mullis <[email protected]>
Cc: Geert Uytterhoeven <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
Diffstat (limited to 'lib/bitmap.c')
0 files changed, 0 insertions, 0 deletions
