Sorting Algorithm
Summary
There are a lot of sorting algorithms, I have only done on a part of the exercises and tests, and there are a lot of tests that are not tested because of their time complexity (e.g. bogo sort) or implementation complexity (e.g. tim sort). Here are some of the tests I did:
- Comparison sorts
- binary_tree_sort
- bubble_sort
- comb_sort
- heap_sort
- insertion_sort
- merge_sort
- odd_even_sort
- quick_sort
- selection_sort
- shell_sort
- smooth_sort
- Non-comparison sorts
- bucket_sort
- counting_sort
- radix_sort
- Other
- sleep_sort
Overview
The following information is in my algorithm implementation.
Binary tree sort
| Best time complexity | Worst time complexity | Average time complexity | Memory | Stable | Source code |
|---|---|---|---|---|---|
| O(nlog(n)) | O(nlog(n)) | O(nlog(n)) | O(n) | Yes | binary_tree_sort.cc |
Dynamic display
None.
Bubble sort
| Best time complexity | Worst time complexity | Average time complexity | Memory | Stable | Source code |
|---|---|---|---|---|---|
| O(n) | O(n²) | O(n²) | O(1) | Yes | bubble_sort.cc |
Dynamic display

Bucket sort
| Best time complexity | Worst time complexity | Average time complexity | Memory | Stable | Source code |
|---|---|---|---|---|---|
| O(n+k) | O(n²) | O(n+k) | O(n+k) | Yes | bucket_sort.cc |
Dynamic display
None.
Comb sort
| Best time complexity | Worst time complexity | Average time complexity | Memory | Stable | Source code |
|---|---|---|---|---|---|
| O(nlog(n)) | O(n²) | O(n²/(2^p)) | O(1) | No | comb_sort.cc |
Dynamic display

Counting sort
| Best time complexity | Worst time complexity | Average time complexity | Memory | Stable | Source code |
|---|---|---|---|---|---|
| - | O(n+r) | O(n+r) | O(n+r) | Yes | counting_sort.cc |
Dynamic display
None.
Heap sort
| Best time complexity | Worst time complexity | Average time complexity | Memory | Stable | Source code |
|---|---|---|---|---|---|
| O(nlog(n)) | O(nlog(n)) | O(nlog(n)) | O(1) | No | heap_sort.cc |
Dynamic display

Insertion sort
| Best time complexity | Worst time complexity | Average time complexity | Memory | Stable | Source code |
|---|---|---|---|---|---|
| O(n) | O(n²) | O(n²) | O(1) | Yes | insertion_sort.cc |
Dynamic display

Merge sort
| Best time complexity | Worst time complexity | Average time complexity | Memory | Stable | Source code |
|---|---|---|---|---|---|
| O(nlog(n)) | O(nlog(n)) | O(nlog(n)) | O(n) | Yes | merge_sort.cc |
Dynamic display

Odd even sort
| Best time complexity | Worst time complexity | Average time complexity | Memory | Stable | Source code |
|---|---|---|---|---|---|
| O(n) | O(n²) | O(n²) | O(1) | Yes | odd_even_sort.cc |
Dynamic display

Quick sort
| Best time complexity | Worst time complexity | Average time complexity | Memory | Stable | Source code |
|---|---|---|---|---|---|
| O(nlog(n)) | O(n²) | O(nlog(n)) | O(log(n)) | No | quick_sort.cc |
Dynamic display

Radix sort
| Best time complexity | Worst time complexity | Average time complexity | Memory | Stable | Source code |
|---|---|---|---|---|---|
| O(n) | - | O(wn) | O(w+n) | Tes | radix_sort.cc |
Dynamic display
None.
Selection sort
| Best time complexity | Worst time complexity | Average time complexity | Memory | Stable | Source code |
|---|---|---|---|---|---|
| O(n²) | O(n²) | O(n²) | O(1) | No | selection_sort.cc |
Dynamic display

Shell sort
| Best time complexity | Worst time complexity | Average time complexity | Memory | Stable | Source code |
|---|---|---|---|---|---|
| O(n^(7/6)) | O(n^(4/3)) | - | O(1) | No | shell_sort.cc |
Dynamic display

Sleep sort
| Best time complexity | Worst time complexity | Average time complexity | Memory | Stable | Source code |
|---|---|---|---|---|---|
| O(1) | - | - | O(n) | No | sleep_sort.cc |
Dynamic display
None.
Smooth sort
| Best time complexity | Worst time complexity | Average time complexity | Memory | Stable | Source code |
|---|---|---|---|---|---|
| O(n) | O(nlog(n)) | O(nlog(n)) | O(1) | No | smooth_sort.cc |
Dynamic display

Test
I chose some of the sorting algorithms that are commonly used or work better to show their performances in various orders of magnitude, and compared them to std::sort. (Only for integers)
- Small amount of data (In microseconds)
| Sorting algorithm | 16 | 32 | 64 | 128 | 512 | 1024 |
|---|---|---|---|---|---|---|
| Bubble sort | 0.718460μs | 2.323331μs | 8.742816μs | 30.240628μs | 451.183452μs | 1876.617118μs |
| Insertion sort | 0.354564μs | 0.662476μs | 1.502234μs | 4.077493μs | 39.589937μs | 134.445298μs |
| Selection sort | 0.615823μs | 1.726170μs | 4.404065μs | 13.939987μs | 150.167438μs | 493.693882μs |
| Merge sort | 4.292098μs | 9.013405μs | 18.521335μs | 39.645921μs | 155.457916μs | 311.587638μs |
| Heap sort | 0.802436μs | 1.642194μs | 4.208122μs | 10.273043μs | 48.155471μs | 102.982355μs |
| Quick sort | 1.427589μs | 2.202033μs | 4.758630μs | 9.097381μs | 40.513671μs | 84.237084μs |
| Shell sort | 0.690468μs | 1.091686μs | 2.957815μs | 6.680743μs | 36.912041μs | 87.633440μs |
| Smooth sort | 1.045032μs | 2.649904μs | 6.475469μs | 15.134310μs | 77.033824μs | 168.044959μs |
| Comb sort | 0.513186μs | 1.110347μs | 2.351323μs | 5.514413μs | 28.999652μs | 62.673958μs |
| std::sort | 0.438540μs | 0.821097μs | 2.621912μs | 5.924961μs | 31.798846μs | 66.770113μs |
- Large amount of data (In milliseconds)
| Sorting algorithm | 10000 | 100000 | 1000000 |
|---|---|---|---|
| Bubble sort | 192.724614ms | 15324.636641ms | 551999.618190ms |
| Insertion sort | 11.071746ms | 1199.033438ms | 140489.051698ms |
| Selection sort | 39.881986ms | 3896.193842ms | 394233.806428ms |
| Merge sort | 3.423321ms | 32.797505ms | 336.168389ms |
| Heap sort | 1.547394ms | 17.826575ms | 282.484509ms |
| Quick sort | 1.045033ms | 8.998943ms | 78.881106ms |
| Shell sort | 1.200761ms | 15.585073ms | 180.192715ms |
| Smooth sort | 2.136252ms | 25.397649ms | 350.425244ms |
| Comb sort | 0.988116ms | 10.678459ms | 126.565752ms |
| std::sort | 0.845077ms | 10.250556ms | 104.314305ms |
From the above table, we can see that (In my sorting algorithms implementation):
- When the amount of data is less than 128,
insertion_sortis more advantageous. - When the amount of data is between 128 and 10000,
comb_sortis more advantageous. - When the amount of data is greater than 10000,
quick_sortis more advantageous.
In order to get more accurate data, I have done a further test.
| Sorting algorithm | 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096 | 8192 | 10000 | 100000 | 1000000 | 10000000 | 100000000 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Insertion sort | 0.401218μs | 0.690468μs | 1.558218μs | 4.198791μs | 13.090898μs | 45.300293μs | 167.597088μs | 518.410767μs | 2153.046876μs | 9295.592109μs | - | - | - | - | - |
| Comb sort | 0.606492μs | 1.250307μs | 2.836517μs | 6.494131μs | 16.561899μs | 36.277557μs | 84.600980μs | 163.528925μs | 330.892747μs | 747.338199μs | 0.901061ms | 12.528727ms | 140.981603ms | 1540.349918ms | 16413.311661ms |
| Quick sort | 1.166331μs | 2.286009μs | 4.870598μs | 10.459656μs | 22.356231μs | 47.968858μs | 102.991685μs | 180.827946μs | 386.783325μs | 804.982939μs | 0.942489ms | 10.484755ms | 91.543914ms | 865.948456ms | 8535.924019ms |
| std::sort | 0.485194μs | 0.951726μs | 2.799194μs | 6.596768μs | 14.947697μs | 33.711629μs | 74.971752μs | 138.485468μs | 308.657814μs | 629.482793μs | 0.817458ms | 9.687451ms | 100.566277ms | 961.007785ms | 9889.731343ms |
Now I am sure that:
- When the amount of data is less than 256,
insertion_sorthas a very good performance, even better thanstd::sort. - When the amount of data is between 256 and 10000, the performance of
comb_sortis slightly better thanquick_sort. - When the amount of data is between 256 and 100000, the performance of
std::sortis the best. - When the amount of data is greater than 100000, the performance of
std::sortis not as good asquick_sort.
How can I beat std::sort? So I referred to the practice of introsort, but did not control the split depth. I call it Impro sort, and now use it to compare with quick_sort and std::sort.
| Sorting algorithm | 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096 | 8192 | 10000 | 100000 | 1000000 | 10000000 | 100000000 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Quick sort | 1.166331μs | 2.286009μs | 4.870598μs | 10.459656μs | 22.356231μs | 47.968858μs | 102.991685μs | 180.827946μs | 386.783325μs | 804.982939μs | 0.942489ms | 10.484755ms | 91.543914ms | 865.948456ms | 8535.924019ms |
| Impro sort | 0.466531μs | 0.886410μs | 2.108721μs | 6.326164μs | 12.363079μs | 27.637313μs | 59.771987μs | 125.935454μs | 278.136618μs | 479.678131μs | 0.617594ms | 7.230302ms | 84.720028ms | 724.386383ms | 7360.014444ms |
| std::sort | 0.485194μs | 0.951726μs | 2.799194μs | 6.596768μs | 14.947697μs | 33.711629μs | 74.971752μs | 138.485468μs | 308.657814μs | 629.482793μs | 0.817458ms | 9.687451ms | 100.566277ms | 961.007785ms | 9889.731343ms |
From the latest test can be seen, no matter in which respect, Impro sort havs improved than Quick sort, that's why I call it Impro sort, which means "Improved sort". And in my test, Impro sort achieved a comprehensive victory, even faster than std::sort. Oh yeah! Although the results may not be so accurate, this shows that there is space for improvement in sorting algorithm, and we can do better through our efforts.