Spreadsort
Sorting algorithm invented by Steven J. Ross
- 18 min read
- 3 chapters
Related on Lably
Through Quicksort
Quicksort identifies a pivot element in the list and then partitions the list into two sublists, those elements less than the pivot and those greater than the pivot. Spreadsort generalizes this idea by partitioning the list into n/c partitions at each step, where n is the total number of elements in the list and c is a small constant (in practice usually between 4 and 8 when comparisons are slow, or much larger in situations where they are fast). It uses distribution-based techniques to accomplish this, first locating the minimum and maximum value in the list, and then dividing the region between them into n/c equal-sized bins. Where caching is an issue, it can help to have a maximum number of bins in each recursive division step, causing this division process to take multiple steps. Though this causes more iterations, it reduces cache misses and can make the algorithm run faster overall.
In the case where the number of bins is at least the number of elements, spreadsort degenerates to bucket sort and the sort completes. Otherwise, each bin is sorted recursively. The algorithm uses heuristic tests to determine whether each bin would be more efficiently sorted by spreadsort or some other classical sort algorithm, then recursively sorts the bin.
Like other distribution-based sorts, spreadsort has the weakness that the programmer is required to provide a means of converting each element into a numeric key, for the purpose of identifying which bin it falls in. Although it is possible to do this for arbitrary-length elements such as strings by considering each element to be followed by an infinite number of minimum values, and indeed for any datatype possessing a total order, this can be more difficult to implement correctly than a simple comparison function, especially on complex structures. Poor implementation of this value function can result in clustering that harms the algorithm's relative performance.
Performance
The worst-case performance of spreadsort is O(n log n) for small data sets, as it uses introsort as a fallback. In the case of distributions where the size of the key in bits k times 2 is roughly the square of the log of the list size n or smaller (2k < (log n)2), it does better in the worst case, achieving O(n √k - log n) worst-case time for the originally published version, and O(n·((k/s) + s)) for the cache aware version. For many real sorting problems with over 1000 items, including string sorting, this asymptotic worst-case is better than O(n log n).
Experiments were done comparing an optimized version of spreadsort to the highly optimized C++ std::sort, implemented with introsort. On lists of integers and floats spreadsort shows a roughly 2–7× runtime improvement for random data on various operating systems.
In space performance, spreadsort is worse than most in-place algorithms: in its simplest form, it is not an in-place algorithm, using O(n) extra space; in experiments, about 20% more than quicksort using a c of 4–8. With a cache-aware form (as included in Boost.Sort), less memory is used and there is an upper bound on memory usage of the maximum bin count times the maximum number of recursions, which ends up being a few kilobytes times the size of the key in bytes. Although it uses asymptotically more space than the O(log n) overhead of quicksort or the O(1) overhead of heapsort, it uses considerably less space than the basic form of mergesort, which uses auxiliary space equal to the space occupied by the list.
Sign in to keep reading
2 more chapters are free with a Lably account.
Implementation
<span id="mwPg"></span><span class="kt" id="mwPw">unsigned</span><span class="w" id="mwQA"> </span> <span class="nf" id="mwQQ">RoughLog2</span><span class="p" id="mwQg">(</span><span class="n" id="mwQw">DATATYPE</span><span class="w" id="mwRA"> </span><span class="n" id="mwRQ">input</span><span class="p" id="mwRg">)</span><span class="w" id="mwRw"> </span> <span class="p" id="mwSA">{</span> <span class="w" id="mwSQ"> </span><span class="kt" id="mwSg">unsigned</span><span class="w" id="mwSw"> </span><span class="kt" id="mwTA">char</span><span class="w" id="mwTQ"> </span><span class="n" id="mwTg">cResult</span><span class="w" id="mwTw"> </span><span class="o" id="mwUA">=</span><span class="w" id="mwUQ"> </span><span class="mi" id="mwUg">0</span><span class="p" id="mwUw">;</span> <span class="w" id="mwVA"> </span><span class="c1" id="mwVQ">// The && is necessary on some compilers to avoid infinite loops; it doesn't</span> <span class="w" id="mwVg"> </span><span class="c1" id="mwVw">// significantly impair performance</span> <span class="w" id="mwWA"> </span><span class="k" id="mwWQ">if</span><span class="w" id="mwWg"> </span><span class="p" id="mwWw">(</span><span class="n" id="mwXA">input</span><span class="w" id="mwXQ"> </span><span class="o" id="mwXg">>=</span><span class="w" id="mwXw"> </span><span class="mi" id="mwYA">0</span><span class="p" id="mwYQ">)</span> <span class="w" id="mwYg"> </span><span class="k" id="mwYw">while</span><span class="w" id="mwZA"> </span><span class="p" id="mwZQ">((</span><span class="n" id="mwZg">input</span><span class="w" id="mwZw"> </span><span class="o" id="mwaA">>></span><span class="w" id="mwaQ"> </span><span class="n" id="mwag">cResult</span><span class="p" id="mwaw">)</span><span class="w" id="mwbA"> </span><span class="o" id="mwbQ">&&</span><span class="w" id="mwbg"> </span><span class="p" id="mwbw">(</span><span class="n" id="mwcA">cResult</span><span class="w" id="mwcQ"> </span><span class="o" id="mwcg"><</span><span class="w" id="mwcw"> </span><span class="n" id="mwdA">DATA_SIZE</span><span class="p" id="mwdQ">))</span><span class="w" id="mwdg"> </span><span class="n" id="mwdw">cResult</span><span class="o" id="mweA">++</span><span class="p" id="mweQ">;</span> <span class="w" id="mweg"> </span><span class="k" id="mwew">else</span> <span class="w" id="mwfA"> </span><span class="k" id="mwfQ">while</span><span class="w" id="mwfg"> </span><span class="p" id="mwfw">(((</span><span class="n" id="mwgA">input</span><span class="w" id="mwgQ"> </span><span class="o" id="mwgg">>></span><span class="w" id="mwgw"> </span><span class="n" id="mwhA">cResult</span><span class="p" id="mwhQ">)</span><span class="w" id="mwhg"> </span><span class="o" id="mwhw"><</span><span class="w" id="mwiA"> </span><span class="mi" id="mwiQ">-1</span><span class="p" id="mwig">)</span><span class="w" id="mwiw"> </span><span class="o" id="mwjA">&&</span><span class="w" id="mwjQ"> </span><span class="p" id="mwjg">(</span><span class="n" id="mwjw">cResult</span><span class="w" id="mwkA"> </span><span class="o" id="mwkQ"><</span><span class="w" id="mwkg"> </span><span class="n" id="mwkw">DATA_SIZE</span><span class="p" id="mwlA">))</span><span class="w" id="mwlQ"> </span><span class="n" id="mwlg">cResult</span><span class="o" id="mwlw">++</span><span class="p" id="mwmA">;</span> <span class="w" id="mwmQ"> </span><span class="k" id="mwmg">return</span><span class="w" id="mwmw"> </span><span class="n" id="mwnA">cResult</span><span class="p" id="mwnQ">;</span> <span class="p" id="mwng">}</span> <span class="n" id="mwnw">SIZETYPE</span> <span class="nf" id="mwoA">GetMaxCount</span><span class="p" id="mwoQ">(</span><span class="kt" id="mwog">unsigned</span><span class="w" id="mwow"> </span><span class="n" id="mwpA">logRange</span><span class="p" id="mwpQ">,</span><span class="w" id="mwpg"> </span><span class="kt" id="mwpw">unsigned</span><span class="w" id="mwqA"> </span><span class="n" id="mwqQ">uCount</span><span class="p" id="mwqg">)</span> <span class="p" id="mwqw">{</span> <span class="w" id="mwrA"> </span><span class="kt" id="mwrQ">unsigned</span><span class="w" id="mwrg"> </span><span class="n" id="mwrw">logSize</span><span class="w" id="mwsA"> </span><span class="o" id="mwsQ">=</span><span class="w" id="mwsg"> </span><span class="n" id="mwsw">RoughLog2Size</span><span class="p" id="mwtA">(</span><span class="n" id="mwtQ">uCount</span><span class="p" id="mwtg">);</span> <span class="w" id="mwtw"> </span><span class="kt" id="mwuA">unsigned</span><span class="w" id="mwuQ"> </span><span class="n" id="mwug">uRelativeWidth</span><span class="w" id="mwuw"> </span><span class="o" id="mwvA">=</span><span class="w" id="mwvQ"> </span><span class="p" id="mwvg">(</span><span class="n" id="mwvw">LOG_CONST</span><span class="w" id="mwwA"> </span><span class="o" id="mwwQ">*</span><span class="w" id="mwwg"> </span><span class="n" id="mwww">logRange</span><span class="p" id="mwxA">)</span><span class="o" id="mwxQ">/</span><span class="p" id="mwxg">((</span><span class="n" id="mwxw">logSize</span><span class="w" id="mwyA"> </span><span class="o" id="mwyQ">></span><span class="w" id="mwyg"> </span><span class="n" id="mwyw">MAX_SPLITS</span><span class="p" id="mwzA">)</span><span class="w" id="mwzQ"> </span><span class="o" id="mwzg">?</span><span class="w" id="mwzw"> </span><span class="n" id="mw0A">MAX_SPLITS</span><span class="w" id="mw0Q"> </span><span class="o" id="mw0g">:</span><span class="w" id="mw0w"> </span><span class="n" id="mw1A">logSize</span><span class="p" id="mw1Q">);</span> <span class="w" id="mw1g"> </span><span class="c1" id="mw1w">// Don't try to bitshift more than the size of an element</span> <span class="w" id="mw2A"> </span><span class="k" id="mw2Q">if</span><span class="w" id="mw2g"> </span><span class="p" id="mw2w">(</span><span class="n" id="mw3A">DATA_SIZE</span><span class="w" id="mw3Q"> </span><span class="o" id="mw3g"><=</span><span class="w" id="mw3w"> </span><span class="n" id="mw4A">uRelativeWidth</span><span class="p" id="mw4Q">)</span> <span class="w" id="mw4g"> </span><span class="n" id="mw4w">uRelativeWidth</span><span class="w" id="mw5A"> </span><span class="o" id="mw5Q">=</span><span class="w" id="mw5g"> </span><span class="n" id="mw5w">DATA_SIZE</span><span class="w" id="mw6A"> </span><span class="o" id="mw6Q">-</span><span class="w" id="mw6g"> </span><span class="mi" id="mw6w">1</span><span class="p" id="mw7A">;</span> <span class="w" id="mw7Q"> </span><span class="k" id="mw7g">return</span><span class="w" id="mw7w"> </span><span class="mi" id="mw8A">1</span><span class="w" id="mw8Q"> </span><span class="o" id="mw8g"><<</span><span class="w" id="mw8w"> </span><span class="p" id="mw9A">((</span><span class="n" id="mw9Q">uRelativeWidth</span><span class="w" id="mw9g"> </span><span class="o" id="mw9w"><</span><span class="w" id="mw-A"> </span><span class="p" id="mw-Q">(</span><span class="n" id="mw-g">LOG_MEAN_BIN_SIZE</span><span class="w" id="mw-w"> </span><span class="o" id="mw_A">+</span><span class="w" id="mw_Q"> </span><span class="n" id="mw_g">LOG_MIN_SPLIT_COUNT</span><span class="p" id="mw_w">))</span><span class="w" id="mwAQA"> </span><span class="o" id="mwAQE">?</span><span class="w" id="mwAQI"> </span> <span class="w" id="mwAQM"> </span><span class="p" id="mwAQQ">(</span><span class="n" id="mwAQU">LOG_MEAN_BIN_SIZE</span><span class="w" id="mwAQY"> </span><span class="o" id="mwAQc">+</span><span class="w" id="mwAQg"> </span><span class="n" id="mwAQk">LOG_MIN_SPLIT_COUNT</span><span class="p" id="mwAQo">)</span><span class="w" id="mwAQs"> </span><span class="o" id="mwAQw">:</span><span class="w" id="mwAQ0"> </span><span class="n" id="mwAQ4">uRelativeWidth</span><span class="p" id="mwAQ8">);</span> <span class="p" id="mwARA">}</span> <span class="kt" id="mwARE">void</span><span class="w" id="mwARI"> </span> <span class="nf" id="mwARM">FindExtremes</span><span class="p" id="mwARQ">(</span><span class="n" id="mwARU">DATATYPE</span><span class="w" id="mwARY"> </span><span class="o" id="mwARc">*</span><span class="n" id="mwARg">Array</span><span class="p" id="mwARk">,</span><span class="w" id="mwARo"> </span><span class="n" id="mwARs">SIZETYPE</span><span class="w" id="mwARw"> </span><span class="n" id="mwAR0">uCount</span><span class="p" id="mwAR4">,</span><span class="w" id="mwAR8"> </span><span class="n" id="mwASA">DATATYPE</span><span class="w" id="mwASE"> </span><span class="o" id="mwASI">&</span><span class="w" id="mwASM"> </span><span class="n" id="mwASQ">piMax</span><span class="p" id="mwASU">,</span><span class="w" id="mwASY"> </span><span class="n" id="mwASc">DATATYPE</span><span class="w" id="mwASg"> </span><span class="o" id="mwASk">&</span><span class="w" id="mwASo"> </span><span class="n" id="mwASs">piMin</span><span class="p" id="mwASw">)</span> <span class="p" id="mwAS0">{</span> <span class="w" id="mwAS4"> </span><span class="n" id="mwAS8">SIZETYPE</span><span class="w" id="mwATA"> </span><span class="n" id="mwATE">u</span><span class="p" id="mwATI">;</span> <span class="w" id="mwATM"> </span><span class="n" id="mwATQ">piMin</span><span class="w" id="mwATU"> </span><span class="o" id="mwATY">=</span><span class="w" id="mwATc"> </span><span class="n" id="mwATg">piMax</span><span class="w" id="mwATk"> </span><span class="o" id="mwATo">=</span><span class="w" id="mwATs"> </span><span class="n" id="mwATw">Array</span><span class="p" id="mwAT0">[</span><span class="mi" id="mwAT4">0</span><span class="p" id="mwAT8">];</span> <span class="w" id="mwAUA"> </span><span class="k" id="mwAUE">for</span><span class="w" id="mwAUI"> </span><span class="p" id="mwAUM">(</span><span class="n" id="mwAUQ">u</span><span class="w" id="mwAUU"> </span><span class="o" id="mwAUY">=</span><span class="w" id="mwAUc"> </span><span class="mi" id="mwAUg">1</span><span class="p" id="mwAUk">;</span><span class="w" id="mwAUo"> </span><span class="n" id="mwAUs">u</span><span class="w" id="mwAUw"> </span><span class="o" id="mwAU0"><</span><span class="w" id="mwAU4"> </span><span class="n" id="mwAU8">uCount</span><span class="p" id="mwAVA">;</span><span class="w" id="mwAVE"> </span><span class="o" id="mwAVI">++</span><span class="n" id="mwAVM">u</span><span class="p" id="mwAVQ">)</span><span class="w" id="mwAVU"> </span><span class="p" id="mwAVY">{</span> <span class="w" id="mwAVc"> </span><span class="k" id="mwAVg">if</span><span class="w" id="mwAVk"> </span><span class="p" id="mwAVo">(</span><span class="n" id="mwAVs">Array</span><span class="p" id="mwAVw">[</span><span class="n" id="mwAV0">u</span><span class="p" id="mwAV4">]</span><span class="w" id="mwAV8"> </span><span class="o" id="mwAWA">></span><span class="w" id="mwAWE"> </span><span class="n" id="mwAWI">piMax</span><span class="p" id="mwAWM">)</span> <span class="w" id="mwAWQ"> </span><span class="n" id="mwAWU">piMax</span><span class="w" id="mwAWY"> </span><span class="o" id="mwAWc">=</span><span class="w" id="mwAWg"> </span><span class="n" id="mwAWk">Array</span><span class="p" id="mwAWo">[</span><span class="n" id="mwAWs">u</span><span class="p" id="mwAWw">];</span> <span class="w" id="mwAW0"> </span><span class="k" id="mwAW4">else</span><span class="w" id="mwAW8"> </span><span class="k" id="mwAXA">if</span><span class="w" id="mwAXE"> </span><span class="p" id="mwAXI">(</span><span class="n" id="mwAXM">Array</span><span class="p" id="mwAXQ">[</span><span class="n" id="mwAXU">u</span><span class="p" id="mwAXY">]</span><span class="w" id="mwAXc"> </span><span class="o" id="mwAXg"><</span><span class="w" id="mwAXk"> </span><span class="n" id="mwAXo">piMin</span><span class="p" id="mwAXs">)</span> <span class="w" id="mwAXw"> </span><span class="n" id="mwAX0">piMin</span><span class="w" id="mwAX4"> </span><span class="o" id="mwAX8">=</span><span class="w" id="mwAYA"> </span><span class="n" id="mwAYE">Array</span><span class="p" id="mwAYI">[</span><span class="n" id="mwAYM">u</span><span class="p" id="mwAYQ">];</span> <span class="w" id="mwAYU"> </span><span class="p" id="mwAYY">}</span> <span class="p" id="mwAYc">}</span><span class="w" id="mwAYg"> </span> <span class="c1" id="mwAYk">//---------------------SpreadSort Source-----------------</span> <span class="n" id="mwAYo">Bin</span><span class="w" id="mwAYs"> </span><span class="o" id="mwAYw">*</span> <span class="nf" id="mwAY0">SpreadSortCore</span><span class="p" id="mwAY4">(</span><span class="n" id="mwAY8">DATATYPE</span><span class="w" id="mwAZA"> </span><span class="o" id="mwAZE">*</span><span class="n" id="mwAZI">Array</span><span class="p" id="mwAZM">,</span><span class="w" id="mwAZQ"> </span><span class="n" id="mwAZU">SIZETYPE</span><span class="w" id="mwAZY"> </span><span class="n" id="mwAZc">uCount</span><span class="p" id="mwAZg">,</span><span class="w" id="mwAZk"> </span><span class="n" id="mwAZo">SIZETYPE</span><span class="w" id="mwAZs"> </span><span class="o" id="mwAZw">&</span><span class="w" id="mwAZ0"> </span><span class="n" id="mwAZ4">uBinCount</span><span class="p" id="mwAZ8">,</span><span class="w" id="mwAaA"> </span><span class="n" id="mwAaE">DATATYPE</span><span class="w" id="mwAaI"> </span><span class="o" id="mwAaM">&</span><span class="n" id="mwAaQ">iMax</span><span class="p" id="mwAaU">,</span><span class="w" id="mwAaY"> </span><span class="n" id="mwAac">DATATYPE</span><span class="w" id="mwAag"> </span><span class="o" id="mwAak">&</span><span class="n" id="mwAao">iMin</span><span class="p" id="mwAas">)</span> <span class="p" id="mwAaw">{</span> <span class="w" id="mwAa0"> </span><span class="c1" id="mwAa4">// This step is roughly 10% of runtime but it helps avoid worst-case</span> <span class="w" id="mwAa8"> </span><span class="c1" id="mwAbA">// behavior and improves behavior with real data. If you know the</span> <span class="w" id="mwAbE"> </span><span class="c1" id="mwAbI">// maximum and minimum ahead of time, you can pass those values in</span> <span class="w" id="mwAbM"> </span><span class="c1" id="mwAbQ">// and skip this step for the first iteration</span> <span class="w" id="mwAbU"> </span><span class="n" id="mwAbY">FindExtremes</span><span class="p" id="mwAbc">((</span><span class="n" id="mwAbg">DATATYPE</span><span class="w" id="mwAbk"> </span><span class="o" id="mwAbo">*</span><span class="p" id="mwAbs">)</span><span class="w" id="mwAbw"> </span><span class="n" id="mwAb0">Array</span><span class="p" id="mwAb4">,</span><span class="w" id="mwAb8"> </span><span class="n" id="mwAcA">uCount</span><span class="p" id="mwAcE">,</span><span class="w" id="mwAcI"> </span><span class="n" id="mwAcM">iMax</span><span class="p" id="mwAcQ">,</span><span class="w" id="mwAcU"> </span><span class="n" id="mwAcY">iMin</span><span class="p" id="mwAcc">);</span> <span class="w" id="mwAcg"> </span><span class="k" id="mwAck">if</span><span class="w" id="mwAco"> </span><span class="p" id="mwAcs">(</span><span class="n" id="mwAcw">iMax</span><span class="w" id="mwAc0"> </span><span class="o" id="mwAc4">==</span><span class="w" id="mwAc8"> </span><span class="n" id="mwAdA">iMin</span><span class="p" id="mwAdE">)</span> <span class="w" id="mwAdI"> </span><span class="k" id="mwAdM">return</span><span class="w" id="mwAdQ"> </span><span class="nb" id="mwAdU">NULL</span><span class="p" id="mwAdY">;</span> <span class="w" id="mwAdc"> </span><span class="n" id="mwAdg">DATATYPE</span><span class="w" id="mwAdk"> </span><span class="n" id="mwAdo">divMin</span><span class="p" id="mwAds">,</span><span class="n" id="mwAdw">divMax</span><span class="p" id="mwAd0">;</span> <span class="w" id="mwAd4"> </span><span class="n" id="mwAd8">SIZETYPE</span><span class="w" id="mwAeA"> </span><span class="n" id="mwAeE">u</span><span class="p" id="mwAeI">;</span> <span class="w" id="mwAeM"> </span><span class="kt" id="mwAeQ">int</span><span class="w" id="mwAeU"> </span><span class="n" id="mwAeY">LogDivisor</span><span class="p" id="mwAec">;</span> <span class="w" id="mwAeg"> </span><span class="n" id="mwAek">Bin</span><span class="w" id="mwAeo"> </span><span class="o" id="mwAes">*</span><span class="w" id="mwAew"> </span><span class="n" id="mwAe0">BinArray</span><span class="p" id="mwAe4">;</span> <span class="w" id="mwAe8"> </span><span class="n" id="mwAfA">Bin</span><span class="o" id="mwAfE">*</span><span class="w" id="mwAfI"> </span><span class="n" id="mwAfM">CurrentBin</span><span class="p" id="mwAfQ">;</span> <span class="w" id="mwAfU"> </span><span class="kt" id="mwAfY">unsigned</span><span class="w" id="mwAfc"> </span><span class="n" id="mwAfg">logRange</span><span class="p" id="mwAfk">;</span> <span class="w" id="mwAfo"> </span><span class="n" id="mwAfs">logRange</span><span class="w" id="mwAfw"> </span><span class="o" id="mwAf0">=</span><span class="w" id="mwAf4"> </span><span class="n" id="mwAf8">RoughLog2Size</span><span class="p" id="mwAgA">((</span><span class="n" id="mwAgE">SIZETYPE</span><span class="p" id="mwAgI">)</span><span class="n" id="mwAgM">iMax</span><span class="o" id="mwAgQ">-</span><span class="n" id="mwAgU">iMin</span><span class="p" id="mwAgY">);</span> <span class="w" id="mwAgc"> </span><span class="k" id="mwAgg">if</span><span class="w" id="mwAgk"> </span><span class="p" id="mwAgo">((</span><span class="n" id="mwAgs">LogDivisor</span><span class="w" id="mwAgw"> </span><span class="o" id="mwAg0">=</span><span class="w" id="mwAg4"> </span><span class="n" id="mwAg8">logRange</span><span class="w" id="mwAhA"> </span><span class="o" id="mwAhE">-</span><span class="w" id="mwAhI"> </span><span class="n" id="mwAhM">RoughLog2Size</span><span class="p" id="mwAhQ">(</span><span class="n" id="mwAhU">uCount</span><span class="p" id="mwAhY">)</span><span class="w" id="mwAhc"> </span><span class="o" id="mwAhg">+</span><span class="w" id="mwAhk"> </span><span class="n" id="mwAho">LOG_MEAN_BIN_SIZE</span><span class="p" id="mwAhs">)</span><span class="w" id="mwAhw"> </span><span class="o" id="mwAh0"><</span><span class="w" id="mwAh4"> </span><span class="mi" id="mwAh8">0</span><span class="p" id="mwAiA">)</span> <span class="w" id="mwAiE"> </span><span class="n" id="mwAiI">LogDivisor</span><span class="w" id="mwAiM"> </span><span class="o" id="mwAiQ">=</span><span class="w" id="mwAiU"> </span><span class="mi" id="mwAiY">0</span><span class="p" id="mwAic">;</span> <span class="w" id="mwAig"> </span><span class="c1" id="mwAik">// The below if statement is only necessary on systems with high memory</span> <span class="w" id="mwAio"> </span><span class="c1" id="mwAis">// latency relative to processor speed (most modern processors)</span> <span class="w" id="mwAiw"> </span><span class="k" id="mwAi0">if</span><span class="w" id="mwAi4"> </span><span class="p" id="mwAi8">((</span><span class="n" id="mwAjA">logRange</span><span class="w" id="mwAjE"> </span><span class="o" id="mwAjI">-</span><span class="w" id="mwAjM"> </span><span class="n" id="mwAjQ">LogDivisor</span><span class="p" id="mwAjU">)</span><span class="w" id="mwAjY"> </span><span class="o" id="mwAjc">></span><span class="w" id="mwAjg"> </span><span class="n" id="mwAjk">MAX_SPLITS</span><span class="p" id="mwAjo">)</span> <span class="w" id="mwAjs"> </span><span class="n" id="mwAjw">LogDivisor</span><span class="w" id="mwAj0"> </span><span class="o" id="mwAj4">=</span><span class="w" id="mwAj8"> </span><span class="n" id="mwAkA">logRange</span><span class="w" id="mwAkE"> </span><span class="o" id="mwAkI">-</span><span class="w" id="mwAkM"> </span><span class="n" id="mwAkQ">MAX_SPLITS</span><span class="p" id="mwAkU">;</span> <span class="w" id="mwAkY"> </span><span class="n" id="mwAkc">divMin</span><span class="w" id="mwAkg"> </span><span class="o" id="mwAkk">=</span><span class="w" id="mwAko"> </span><span class="n" id="mwAks">iMin</span><span class="w" id="mwAkw"> </span><span class="o" id="mwAk0">>></span><span class="w" id="mwAk4"> </span><span class="n" id="mwAk8">LogDivisor</span><span class="p" id="mwAlA">;</span> <span class="w" id="mwAlE"> </span><span class="n" id="mwAlI">divMax</span><span class="w" id="mwAlM"> </span><span class="o" id="mwAlQ">=</span><span class="w" id="mwAlU"> </span><span class="n" id="mwAlY">iMax</span><span class="w" id="mwAlc"> </span><span class="o" id="mwAlg">>></span><span class="w" id="mwAlk"> </span><span class="n" id="mwAlo">LogDivisor</span><span class="p" id="mwAls">;</span> <span class="w" id="mwAlw"> </span><span class="n" id="mwAl0">uBinCount</span><span class="w" id="mwAl4"> </span><span class="o" id="mwAl8">=</span><span class="w" id="mwAmA"> </span><span class="n" id="mwAmE">divMax</span><span class="w" id="mwAmI"> </span><span class="o" id="mwAmM">-</span><span class="w" id="mwAmQ"> </span><span class="n" id="mwAmU">divMin</span><span class="w" id="mwAmY"> </span><span class="o" id="mwAmc">+</span><span class="w" id="mwAmg"> </span><span class="mi" id="mwAmk">1</span><span class="p" id="mwAmo">;</span> <span class="w" id="mwAms"> </span> <span class="w" id="mwAmw"> </span><span class="c1" id="mwAm0">// Allocate the bins and determine their sizes</span> <span class="w" id="mwAm4"> </span><span class="n" id="mwAm8">BinArray</span><span class="w" id="mwAnA"> </span><span class="o" id="mwAnE">=</span><span class="w" id="mwAnI"> </span><span class="n" id="mwAnM">calloc</span><span class="p" id="mwAnQ">(</span><span class="n" id="mwAnU">uBinCount</span><span class="p" id="mwAnY">,</span><span class="w" id="mwAnc"> </span><span class="k" id="mwAng">sizeof</span><span class="p" id="mwAnk">(</span><span class="n" id="mwAno">Bin</span><span class="p" id="mwAns">));</span> <span class="w" id="mwAnw"> </span><span class="c1" id="mwAn0">// Memory allocation failure check and clean return with sorted results</span> <span class="w" id="mwAn4"> </span><span class="k" id="mwAn8">if</span><span class="w" id="mwAoA"> </span><span class="p" id="mwAoE">(</span><span class="o" id="mwAoI">!</span><span class="n" id="mwAoM">BinArray</span><span class="p" id="mwAoQ">)</span><span class="w" id="mwAoU"> </span><span class="p" id="mwAoY">{</span> <span class="w" id="mwAoc"> </span><span class="n" id="mwAog">printf</span><span class="p" id="mwAok">(</span><span class="s" id="mwAoo">"Using std::sort because of memory allocation failure</span><span class="se" id="mwAos">\n</span><span class="s" id="mwAow">"</span><span class="p" id="mwAo0">);</span> <span class="w" id="mwAo4"> </span><span class="n" id="mwAo8">std</span><span class="o" id="mwApA">::</span><span class="n" id="mwApE">sort</span><span class="p" id="mwApI">(</span><span class="n" id="mwApM">Array</span><span class="p" id="mwApQ">,</span><span class="w" id="mwApU"> </span><span class="n" id="mwApY">Array</span><span class="w" id="mwApc"> </span><span class="o" id="mwApg">+</span><span class="w" id="mwApk"> </span><span class="n" id="mwApo">uCount</span><span class="p" id="mwAps">);</span> <span class="w" id="mwApw"> </span><span class="k" id="mwAp0">return</span><span class="w" id="mwAp4"> </span><span class="nb" id="mwAp8">NULL</span><span class="p" id="mwAqA">;</span> <span class="w" id="mwAqE"> </span><span class="p" id="mwAqI">}</span> <span class="w" id="mwAqM"> </span> <span class="w" id="mwAqQ"> </span><span class="c1" id="mwAqU">// Calculating the size of each bin; this takes roughly 10% of runtime</span> <span class="w" id="mwAqY"> </span><span class="k" id="mwAqc">for</span><span class="w" id="mwAqg"> </span><span class="p" id="mwAqk">(</span><span class="n" id="mwAqo">u</span><span class="w" id="mwAqs"> </span><span class="o" id="mwAqw">=</span><span class="w" id="mwAq0"> </span><span class="mi" id="mwAq4">0</span><span class="p" id="mwAq8">;</span><span class="w" id="mwArA"> </span><span class="n" id="mwArE">u</span><span class="w" id="mwArI"> </span><span class="o" id="mwArM"><</span><span class="w" id="mwArQ"> </span><span class="n" id="mwArU">uCount</span><span class="p" id="mwArY">;</span><span class="w" id="mwArc"> </span><span class="o" id="mwArg">++</span><span class="n" id="mwArk">u</span><span class="p" id="mwAro">)</span> <span class="w" id="mwArs"> </span><span class="n" id="mwArw">BinArray</span><span class="p" id="mwAr0">[(</span><span class="n" id="mwAr4">Array</span><span class="p" id="mwAr8">[</span><span class="n" id="mwAsA">u</span><span class="p" id="mwAsE">]</span><span class="w" id="mwAsI"> </span><span class="o" id="mwAsM">>></span><span class="w" id="mwAsQ"> </span><span class="n" id="mwAsU">LogDivisor</span><span class="p" id="mwAsY">)</span><span class="w" id="mwAsc"> </span><span class="o" id="mwAsg">-</span><span class="w" id="mwAsk"> </span><span class="n" id="mwAso">divMin</span><span class="p" id="mwAss">].</span><span class="n" id="mwAsw">uCount</span><span class="o" id="mwAs0">++</span><span class="p" id="mwAs4">;</span> <span class="w" id="mwAs8"> </span><span class="c1" id="mwAtA">// Assign the bin positions</span> <span class="w" id="mwAtE"> </span><span class="n" id="mwAtI">BinArray</span><span class="p" id="mwAtM">[</span><span class="mi" id="mwAtQ">0</span><span class="p" id="mwAtU">].</span><span class="n" id="mwAtY">CurrentPosition</span><span class="w" id="mwAtc"> </span><span class="o" id="mwAtg">=</span><span class="w" id="mwAtk"> </span><span class="p" id="mwAto">(</span><span class="n" id="mwAts">DATATYPE</span><span class="w" id="mwAtw"> </span><span class="o" id="mwAt0">*</span><span class="p" id="mwAt4">)</span><span class="n" id="mwAt8">Array</span><span class="p" id="mwAuA">;</span> <span class="w" id="mwAuE"> </span><span class="k" id="mwAuI">for</span><span class="w" id="mwAuM"> </span><span class="p" id="mwAuQ">(</span><span class="n" id="mwAuU">u</span><span class="w" id="mwAuY"> </span><span class="o" id="mwAuc">=</span><span class="w" id="mwAug"> </span><span class="mi" id="mwAuk">0</span><span class="p" id="mwAuo">;</span><span class="w" id="mwAus"> </span><span class="n" id="mwAuw">u</span><span class="w" id="mwAu0"> </span><span class="o" id="mwAu4"><</span><span class="w" id="mwAu8"> </span><span class="n" id="mwAvA">uBinCount</span><span class="w" id="mwAvE"> </span><span class="o" id="mwAvI">-</span><span class="w" id="mwAvM"> </span><span class="mi" id="mwAvQ">1</span><span class="p" id="mwAvU">;</span><span class="w" id="mwAvY"> </span><span class="n" id="mwAvc">u</span><span class="o" id="mwAvg">++</span><span class="p" id="mwAvk">)</span><span class="w" id="mwAvo"> </span><span class="p" id="mwAvs">{</span> <span class="w" id="mwAvw"> </span><span class="n" id="mwAv0">BinArray</span><span class="p" id="mwAv4">[</span><span class="n" id="mwAv8">u</span><span class="w" id="mwAwA"> </span><span class="o" id="mwAwE">+</span><span class="w" id="mwAwI"> </span><span class="mi" id="mwAwM">1</span><span class="p" id="mwAwQ">].</span><span class="n" id="mwAwU">CurrentPosition</span><span class="w" id="mwAwY"> </span><span class="o" id="mwAwc">=</span><span class="w" id="mwAwg"> </span><span class="n" id="mwAwk">BinArray</span><span class="p" id="mwAwo">[</span><span class="n" id="mwAws">u</span><span class="p" id="mwAww">].</span><span class="n" id="mwAw0">CurrentPosition</span><span class="w" id="mwAw4"> </span><span class="o" id="mwAw8">+</span><span class="w" id="mwAxA"> </span><span class="n" id="mwAxE">BinArray</span><span class="p" id="mwAxI">[</span><span class="n" id="mwAxM">u</span><span class="p" id="mwAxQ">].</span><span class="n" id="mwAxU">uCount</span><span class="p" id="mwAxY">;</span> <span class="w" id="mwAxc"> </span><span class="n" id="mwAxg">BinArray</span><span class="p" id="mwAxk">[</span><span class="n" id="mwAxo">u</span><span class="p" id="mwAxs">].</span><span class="n" id="mwAxw">uCount</span><span class="w" id="mwAx0"> </span><span class="o" id="mwAx4">=</span><span class="w" id="mwAx8"> </span><span class="n" id="mwAyA">BinArray</span><span class="p" id="mwAyE">[</span><span class="n" id="mwAyI">u</span><span class="p" id="mwAyM">].</span><span class="n" id="mwAyQ">CurrentPosition</span><span class="w" id="mwAyU"> </span><span class="o" id="mwAyY">-</span><span class="w" id="mwAyc"> </span><span class="n" id="mwAyg">Array</span><span class="p" id="mwAyk">;</span> <span class="w" id="mwAyo"> </span><span class="p" id="mwAys">}</span> <span class="w" id="mwAyw"> </span><span class="n" id="mwAy0">BinArray</span><span class="p" id="mwAy4">[</span><span class="n" id="mwAy8">u</span><span class="p" id="mwAzA">].</span><span class="n" id="mwAzE">uCount</span><span class="w" id="mwAzI"> </span><span class="o" id="mwAzM">=</span><span class="w" id="mwAzQ"> </span><span class="n" id="mwAzU">BinArray</span><span class="p" id="mwAzY">[</span><span class="n" id="mwAzc">u</span><span class="p" id="mwAzg">].</span><span class="n" id="mwAzk">CurrentPosition</span><span class="w" id="mwAzo"> </span><span class="o" id="mwAzs">-</span><span class="w" id="mwAzw"> </span><span class="n" id="mwAz0">Array</span><span class="p" id="mwAz4">;</span> <span class="w" id="mwAz8"> </span> <span class="w" id="mwA0A"> </span><span class="c1" id="mwA0E">// Swap into place. This dominates runtime, especially in the swap;</span> <span class="w" id="mwA0I"> </span><span class="c1" id="mwA0M">// std::sort calls are the other main time-user.</span> <span class="w" id="mwA0Q"> </span><span class="k" id="mwA0U">for</span><span class="w" id="mwA0Y"> </span><span class="p" id="mwA0c">(</span><span class="n" id="mwA0g">u</span><span class="w" id="mwA0k"> </span><span class="o" id="mwA0o">=</span><span class="w" id="mwA0s"> </span><span class="mi" id="mwA0w">0</span><span class="p" id="mwA00">;</span><span class="w" id="mwA04"> </span><span class="n" id="mwA08">u</span><span class="w" id="mwA1A"> </span><span class="o" id="mwA1E"><</span><span class="w" id="mwA1I"> </span><span class="n" id="mwA1M">uCount</span><span class="p" id="mwA1Q">;</span><span class="w" id="mwA1U"> </span><span class="o" id="mwA1Y">++</span><span class="n" id="mwA1c">u</span><span class="p" id="mwA1g">)</span><span class="w" id="mwA1k"> </span><span class="p" id="mwA1o">{</span> <span class="w" id="mwA1s"> </span><span class="k" id="mwA1w">for</span><span class="w" id="mwA10"> </span><span class="p" id="mwA14">(</span><span class="n" id="mwA18">CurrentBin</span><span class="w" id="mwA2A"> </span><span class="o" id="mwA2E">=</span><span class="w" id="mwA2I"> </span><span class="n" id="mwA2M">BinArray</span><span class="w" id="mwA2Q"> </span><span class="o" id="mwA2U">+</span><span class="w" id="mwA2Y"> </span><span class="p" id="mwA2c">((</span><span class="n" id="mwA2g">Array</span><span class="p" id="mwA2k">[</span><span class="n" id="mwA2o">u</span><span class="p" id="mwA2s">]</span><span class="w" id="mwA2w"> </span><span class="o" id="mwA20">>></span><span class="w" id="mwA24"> </span><span class="n" id="mwA28">LogDivisor</span><span class="p" id="mwA3A">)</span><span class="w" id="mwA3E"> </span><span class="o" id="mwA3I">-</span><span class="w" id="mwA3M"> </span><span class="n" id="mwA3Q">divMin</span><span class="p" id="mwA3U">);</span><span class="w" id="mwA3Y"> </span><span class="p" id="mwA3c">(</span><span class="n" id="mwA3g">CurrentBin</span><span class="o" id="mwA3k">-></span><span class="n" id="mwA3o">uCount</span><span class="w" id="mwA3s"> </span><span class="o" id="mwA3w">></span><span class="w" id="mwA30"> </span><span class="n" id="mwA34">u</span><span class="p" id="mwA38">);</span><span class="w" id="mwA4A"> </span> <span class="w" id="mwA4E"> </span><span class="n" id="mwA4I">CurrentBin</span><span class="w" id="mwA4M"> </span><span class="o" id="mwA4Q">=</span><span class="w" id="mwA4U"> </span><span class="n" id="mwA4Y">BinArray</span><span class="w" id="mwA4c"> </span><span class="o" id="mwA4g">+</span><span class="w" id="mwA4k"> </span><span class="p" id="mwA4o">((</span><span class="n" id="mwA4s">Array</span><span class="p" id="mwA4w">[</span><span class="n" id="mwA40">u</span><span class="p" id="mwA44">]</span><span class="w" id="mwA48"> </span><span class="o" id="mwA5A">>></span><span class="w" id="mwA5E"> </span><span class="n" id="mwA5I">LogDivisor</span><span class="p" id="mwA5M">)</span><span class="w" id="mwA5Q"> </span><span class="o" id="mwA5U">-</span><span class="w" id="mwA5Y"> </span><span class="n" id="mwA5c">divMin</span><span class="p" id="mwA5g">))</span> <span class="w" id="mwA5k"> </span><span class="n" id="mwA5o">SWAP</span><span class="p" id="mwA5s">(</span><span class="n" id="mwA5w">Array</span><span class="w" id="mwA50"> </span><span class="o" id="mwA54">+</span><span class="w" id="mwA58"> </span><span class="n" id="mwA6A">u</span><span class="p" id="mwA6E">,</span><span class="w" id="mwA6I"> </span><span class="n" id="mwA6M">CurrentBin</span><span class="o" id="mwA6Q">-></span><span class="n" id="mwA6U">CurrentPosition</span><span class="o" id="mwA6Y">++</span><span class="p" id="mwA6c">);</span> <span class="w" id="mwA6g"> </span><span class="c1" id="mwA6k">// Now that we've found the item belonging in this position,</span> <span class="w" id="mwA6o"> </span><span class="c1" id="mwA6s">// increment the bucket count</span> <span class="w" id="mwA6w"> </span><span class="k" id="mwA60">if</span><span class="w" id="mwA64"> </span><span class="p" id="mwA68">(</span><span class="n" id="mwA7A">CurrentBin</span><span class="o" id="mwA7E">-></span><span class="n" id="mwA7I">CurrentPosition</span><span class="w" id="mwA7M"> </span><span class="o" id="mwA7Q">==</span><span class="w" id="mwA7U"> </span><span class="n" id="mwA7Y">Array</span><span class="w" id="mwA7c"> </span><span class="o" id="mwA7g">+</span><span class="w" id="mwA7k"> </span><span class="n" id="mwA7o">u</span><span class="p" id="mwA7s">)</span> <span class="w" id="mwA7w"> </span><span class="o" id="mwA70">++</span><span class="p" id="mwA74">(</span><span class="n" id="mwA78">CurrentBin</span><span class="o" id="mwA8A">-></span><span class="n" id="mwA8E">CurrentPosition</span><span class="p" id="mwA8I">);</span> <span class="w" id="mwA8M"> </span><span class="p" id="mwA8Q">}</span> <span class="w" id="mwA8U"> </span> <span class="w" id="mwA8Y"> </span><span class="c1" id="mwA8c">// If we've bucketsorted, the array is sorted and we should skip recursion</span> <span class="w" id="mwA8g"> </span><span class="k" id="mwA8k">if</span><span class="w" id="mwA8o"> </span><span class="p" id="mwA8s">(</span><span class="o" id="mwA8w">!</span><span class="n" id="mwA80">LogDivisor</span><span class="p" id="mwA84">)</span><span class="w" id="mwA88"> </span><span class="p" id="mwA9A">{</span> <span class="w" id="mwA9E"> </span><span class="n" id="mwA9I">free</span><span class="p" id="mwA9M">(</span><span class="n" id="mwA9Q">BinArray</span><span class="p" id="mwA9U">);</span> <span class="w" id="mwA9Y"> </span><span class="k" id="mwA9c">return</span><span class="w" id="mwA9g"> </span><span class="nb" id="mwA9k">NULL</span><span class="p" id="mwA9o">;</span> <span class="w" id="mwA9s"> </span><span class="p" id="mwA9w">}</span> <span class="w" id="mwA90"> </span><span class="k" id="mwA94">return</span><span class="w" id="mwA98"> </span><span class="n" id="mwA-A">BinArray</span><span class="p" id="mwA-E">;</span> <span class="p" id="mwA-I">}</span> <span class="kt" id="mwA-M">void</span> <span class="nf" id="mwA-Q">SpreadSortBins</span><span class="p" id="mwA-U">(</span><span class="n" id="mwA-Y">DATATYPE</span><span class="w" id="mwA-c"> </span><span class="o" id="mwA-g">*</span><span class="n" id="mwA-k">Array</span><span class="p" id="mwA-o">,</span><span class="w" id="mwA-s"> </span><span class="n" id="mwA-w">SIZETYPE</span><span class="w" id="mwA-0"> </span><span class="n" id="mwA-4">uCount</span><span class="p" id="mwA-8">,</span><span class="w" id="mwA_A"> </span><span class="n" id="mwA_E">SIZETYPE</span><span class="w" id="mwA_I"> </span><span class="n" id="mwA_M">uBinCount</span><span class="p" id="mwA_Q">,</span><span class="w" id="mwA_U"> </span><span class="k" id="mwA_Y">const</span><span class="w" id="mwA_c"> </span><span class="n" id="mwA_g">DATATYPE</span><span class="w" id="mwA_k"> </span><span class="o" id="mwA_o">&</span><span class="n" id="mwA_s">iMax</span> <span class="w" id="mwA_w"> </span><span class="p" id="mwA_0">,</span><span class="w" id="mwA_4"> </span><span class="k" id="mwA_8">const</span><span class="w" id="mwBAA"> </span><span class="n" id="mwBAE">DATATYPE</span><span class="w" id="mwBAI"> </span><span class="o" id="mwBAM">&</span><span class="n" id="mwBAQ">iMin</span><span class="p" id="mwBAU">,</span><span class="w" id="mwBAY"> </span><span class="n" id="mwBAc">Bin</span><span class="w" id="mwBAg"> </span><span class="o" id="mwBAk">*</span><span class="w" id="mwBAo"> </span><span class="n" id="mwBAs">BinArray</span><span class="p" id="mwBAw">,</span><span class="w" id="mwBA0"> </span><span class="n" id="mwBA4">SIZETYPE</span><span class="w" id="mwBA8"> </span><span class="n" id="mwBBA">uMaxCount</span><span class="p" id="mwBBE">)</span> <span class="p" id="mwBBI">{</span> <span class="w" id="mwBBM"> </span><span class="n" id="mwBBQ">SIZETYPE</span><span class="w" id="mwBBU"> </span><span class="n" id="mwBBY">u</span><span class="p" id="mwBBc">;</span> <span class="w" id="mwBBg"> </span><span class="k" id="mwBBk">for</span><span class="w" id="mwBBo"> </span><span class="p" id="mwBBs">(</span><span class="n" id="mwBBw">u</span><span class="w" id="mwBB0"> </span><span class="o" id="mwBB4">=</span><span class="w" id="mwBB8"> </span><span class="mi" id="mwBCA">0</span><span class="p" id="mwBCE">;</span><span class="w" id="mwBCI"> </span><span class="n" id="mwBCM">u</span><span class="w" id="mwBCQ"> </span><span class="o" id="mwBCU"><</span><span class="w" id="mwBCY"> </span><span class="n" id="mwBCc">uBinCount</span><span class="p" id="mwBCg">;</span><span class="w" id="mwBCk"> </span><span class="n" id="mwBCo">u</span><span class="o" id="mwBCs">++</span><span class="p" id="mwBCw">)</span><span class="w" id="mwBC0"> </span><span class="p" id="mwBC4">{</span> <span class="w" id="mwBC8"> </span><span class="n" id="mwBDA">SIZETYPE</span><span class="w" id="mwBDE"> </span><span class="n" id="mwBDI">count</span><span class="w" id="mwBDM"> </span><span class="o" id="mwBDQ">=</span><span class="w" id="mwBDU"> </span><span class="p" id="mwBDY">(</span><span class="n" id="mwBDc">BinArray</span><span class="p" id="mwBDg">[</span><span class="n" id="mwBDk">u</span><span class="p" id="mwBDo">].</span><span class="n" id="mwBDs">CurrentPosition</span><span class="w" id="mwBDw"> </span><span class="o" id="mwBD0">-</span><span class="w" id="mwBD4"> </span><span class="n" id="mwBD8">Array</span><span class="p" id="mwBEA">)</span><span class="w" id="mwBEE"> </span><span class="o" id="mwBEI">-</span><span class="w" id="mwBEM"> </span><span class="n" id="mwBEQ">BinArray</span><span class="p" id="mwBEU">[</span><span class="n" id="mwBEY">u</span><span class="p" id="mwBEc">].</span><span class="n" id="mwBEg">uCount</span><span class="p" id="mwBEk">;</span> <span class="w" id="mwBEo"> </span><span class="c1" id="mwBEs">// Don't sort unless there are at least two items to compare</span> <span class="w" id="mwBEw"> </span><span class="k" id="mwBE0">if</span><span class="w" id="mwBE4"> </span><span class="p" id="mwBE8">(</span><span class="n" id="mwBFA">count</span><span class="w" id="mwBFE"> </span><span class="o" id="mwBFI"><</span><span class="w" id="mwBFM"> </span><span class="mi" id="mwBFQ">2</span><span class="p" id="mwBFU">)</span> <span class="w" id="mwBFY"> </span><span class="k" id="mwBFc">continue</span><span class="p" id="mwBFg">;</span> <span class="w" id="mwBFk"> </span><span class="k" id="mwBFo">if</span><span class="w" id="mwBFs"> </span><span class="p" id="mwBFw">(</span><span class="n" id="mwBF0">count</span><span class="w" id="mwBF4"> </span><span class="o" id="mwBF8"><</span><span class="w" id="mwBGA"> </span><span class="n" id="mwBGE">uMaxCount</span><span class="p" id="mwBGI">)</span> <span class="w" id="mwBGM"> </span><span class="n" id="mwBGQ">std</span><span class="o" id="mwBGU">::</span><span class="n" id="mwBGY">sort</span><span class="p" id="mwBGc">(</span><span class="n" id="mwBGg">Array</span><span class="w" id="mwBGk"> </span><span class="o" id="mwBGo">+</span><span class="w" id="mwBGs"> </span><span class="n" id="mwBGw">BinArray</span><span class="p" id="mwBG0">[</span><span class="n" id="mwBG4">u</span><span class="p" id="mwBG8">].</span><span class="n" id="mwBHA">uCount</span><span class="p" id="mwBHE">,</span><span class="w" id="mwBHI"> </span><span class="n" id="mwBHM">BinArray</span><span class="p" id="mwBHQ">[</span><span class="n" id="mwBHU">u</span><span class="p" id="mwBHY">].</span><span class="n" id="mwBHc">CurrentPosition</span><span class="p" id="mwBHg">);</span> <span class="w" id="mwBHk"> </span><span class="k" id="mwBHo">else</span> <span class="w" id="mwBHs"> </span><span class="n" id="mwBHw">SpreadSortRec</span><span class="p" id="mwBH0">(</span><span class="n" id="mwBH4">Array</span><span class="w" id="mwBH8"> </span><span class="o" id="mwBIA">+</span><span class="w" id="mwBIE"> </span><span class="n" id="mwBII">BinArray</span><span class="p" id="mwBIM">[</span><span class="n" id="mwBIQ">u</span><span class="p" id="mwBIU">].</span><span class="n" id="mwBIY">uCount</span><span class="p" id="mwBIc">,</span><span class="w" id="mwBIg"> </span><span class="n" id="mwBIk">count</span><span class="p" id="mwBIo">);</span> <span class="w" id="mwBIs"> </span><span class="p" id="mwBIw">}</span> <span class="w" id="mwBI0"> </span><span class="n" id="mwBI4">free</span><span class="p" id="mwBI8">(</span><span class="n" id="mwBJA">BinArray</span><span class="p" id="mwBJE">);</span> <span class="p" id="mwBJI">}</span> <span class="kt" id="mwBJM">void</span><span class="w" id="mwBJQ"> </span> <span class="nf" id="mwBJU">SpreadSortRec</span><span class="p" id="mwBJY">(</span><span class="n" id="mwBJc">DATATYPE</span><span class="w" id="mwBJg"> </span><span class="o" id="mwBJk">*</span><span class="n" id="mwBJo">Array</span><span class="p" id="mwBJs">,</span><span class="w" id="mwBJw"> </span><span class="n" id="mwBJ0">SIZETYPE</span><span class="w" id="mwBJ4"> </span><span class="n" id="mwBJ8">uCount</span><span class="p" id="mwBKA">)</span> <span class="p" id="mwBKE">{</span> <span class="w" id="mwBKI"> </span><span class="k" id="mwBKM">if</span><span class="w" id="mwBKQ"> </span><span class="p" id="mwBKU">(</span><span class="n" id="mwBKY">uCount</span><span class="w" id="mwBKc"> </span><span class="o" id="mwBKg"><</span><span class="w" id="mwBKk"> </span><span class="mi" id="mwBKo">2</span><span class="p" id="mwBKs">)</span> <span class="w" id="mwBKw"> </span><span class="k" id="mwBK0">return</span><span class="p" id="mwBK4">;</span><span class="w" id="mwBK8"> </span> <span class="w" id="mwBLA"> </span><span class="n" id="mwBLE">DATATYPE</span><span class="w" id="mwBLI"> </span><span class="n" id="mwBLM">iMax</span><span class="p" id="mwBLQ">,</span><span class="w" id="mwBLU"> </span><span class="n" id="mwBLY">iMin</span><span class="p" id="mwBLc">;</span> <span class="w" id="mwBLg"> </span><span class="n" id="mwBLk">SIZETYPE</span><span class="w" id="mwBLo"> </span><span class="n" id="mwBLs">uBinCount</span><span class="p" id="mwBLw">;</span> <span class="w" id="mwBL0"> </span><span class="n" id="mwBL4">Bin</span><span class="w" id="mwBL8"> </span><span class="o" id="mwBMA">*</span><span class="w" id="mwBME"> </span><span class="n" id="mwBMI">BinArray</span><span class="w" id="mwBMM"> </span><span class="o" id="mwBMQ">=</span><span class="w" id="mwBMU"> </span><span class="n" id="mwBMY">SpreadSortCore</span><span class="p" id="mwBMc">(</span><span class="n" id="mwBMg">Array</span><span class="p" id="mwBMk">,</span><span class="w" id="mwBMo"> </span><span class="n" id="mwBMs">uCount</span><span class="p" id="mwBMw">,</span><span class="w" id="mwBM0"> </span><span class="n" id="mwBM4">uBinCount</span><span class="p" id="mwBM8">,</span><span class="w" id="mwBNA"> </span><span class="n" id="mwBNE">iMax</span><span class="p" id="mwBNI">,</span><span class="w" id="mwBNM"> </span><span class="n" id="mwBNQ">iMin</span><span class="p" id="mwBNU">);</span> <span class="w" id="mwBNY"> </span><span class="k" id="mwBNc">if</span><span class="w" id="mwBNg"> </span><span class="p" id="mwBNk">(</span><span class="o" id="mwBNo">!</span><span class="n" id="mwBNs">BinArray</span><span class="p" id="mwBNw">)</span> <span class="w" id="mwBN0"> </span><span class="k" id="mwBN4">return</span><span class="p" id="mwBN8">;</span> <span class="w" id="mwBOA"> </span><span class="n" id="mwBOE">SpreadSortBins</span><span class="p" id="mwBOI">(</span><span class="n" id="mwBOM">Array</span><span class="p" id="mwBOQ">,</span><span class="w" id="mwBOU"> </span><span class="n" id="mwBOY">uCount</span><span class="p" id="mwBOc">,</span><span class="w" id="mwBOg"> </span><span class="n" id="mwBOk">uBinCount</span><span class="p" id="mwBOo">,</span><span class="w" id="mwBOs"> </span><span class="n" id="mwBOw">iMax</span><span class="p" id="mwBO0">,</span><span class="w" id="mwBO4"> </span><span class="n" id="mwBO8">iMin</span><span class="p" id="mwBPA">,</span><span class="w" id="mwBPE"> </span><span class="n" id="mwBPI">BinArray</span><span class="p" id="mwBPM">,</span> <span class="w" id="mwBPQ"> </span><span class="n" id="mwBPU">GetMaxCount</span><span class="p" id="mwBPY">(</span><span class="n" id="mwBPc">RoughLog2Size</span><span class="p" id="mwBPg">((</span><span class="n" id="mwBPk">SIZETYPE</span><span class="p" id="mwBPo">)</span><span class="n" id="mwBPs">iMax</span><span class="o" id="mwBPw">-</span><span class="n" id="mwBP0">iMin</span><span class="p" id="mwBP4">),</span><span class="w" id="mwBP8"> </span><span class="n" id="mwBQA">uCount</span><span class="p" id="mwBQE">));</span> <span class="p" id="mwBQI">}</span>Two levels are as good as any
An interesting result for algorithms of this general type (splitting based on the radix, then comparison-based sorting) is that they are O(n) for any bounded and integrable probability density function. This result can be obtained by forcing Spreadsort to always iterate one more time if the bin size after the first iteration is above some constant value. If the key density function is known to be Riemann integrable and bounded, this modification of Spreadsort can attain some performance improvement over the basic algorithm, and will have better worst-case performance. If this restriction cannot usually be depended on, this change will add a little extra runtime overhead to the algorithm and gain little. Other similar algorithms are Flashsort (which is simpler) and Adaptive Left Radix. Adaptive Left Radix is apparently quite similar, the main difference being recursive behavior, with Spreadsort checking for worst-case situations and using std::sort to avoid performance problems where necessary, and Adaptive Left Radix recursing continuously until done or the data is small enough to use insertion sort.

