| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- /* Copyright The kNet Project.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License. */
- #pragma once
- /** @file Sort.h
- @brief A range of comparison sort algorithms. */
- #include "Clock.h"
- //#include "LCG.h"
- #include "SortCmp.h"
- namespace kNet
- {
- /** @brief A range of comparison sort algorithms.
- When to use one of these sorts and when to use the std sorts?
- (std::sort, std::stable_sort, std::list::sort etc.)
- 1) Always consider using the standard versions first. For example, the visual c++
- std::sort is on average faster than the introsort described here. Additionally,
- your code has the advantage of being more portable.
- 2) The sorting algorithms described here operate only on contiguous data. This means
- that they can only be used to sort vectors and arrays. If you have a linked
- list, you can only use list::sort. Additionally, the data type T must be assignable.
- 3) If the std:: sorting performance is not acceptable, figure out the "profile"
- of your sortable data. Is it in random or mostly sorted order? Is it sorted
- once, occasionally or on a per-frame basis? Are all items unique or are there several
- that are equivalent? Is stable sort-property required? Then look at the actual
- implementations of these algorithms and decide what fits the data profile the best.
- And of course, always measure the actual performance.
-
- Note that a few of these algorithms have only been implemented as a curiosity.
- Selection sort for example just plain sucks.
- The client-implemented comparison function must be of this form:
- template<typename T>
- int CmpFunc(const T &a, const T &b);
- @param a The first comparison operand.
- @param b The second comparison operand.
- @return a negative value if a < b, 0 if a == b and a positive value when b < a. */
- namespace sort
- {
- /** Selection sort is a stable sort that has FIXED running time of ~n^2/2. It can
- contend only against Bubble sort, which in general performs far better.
- The only advantage of this against other sorts is that CmpFunc can be a partial ordering instead
- of a total ordering (For other sort functions, cmp must be a total order). */
- template<typename T, typename CmpFunc>
- void SelectionSort(T *list, int numItems, CmpFunc &cmp);
- /** The same as above, but only partially sorts the list so that the numItemsToSort first items in the
- list are in order, the rest are unordered. Gives a slight performance boost when only a part of the list
- needs to get ordered. Doesn't affect the asymptotics though, which is O(k*n), where k=numItemsToSort. */
- template<typename T, typename CmpFunc>
- void PartialSelectionSort(T *list, int numItems, int numItemsToSort, CmpFunc &cmp);
- /** Insertion sort is efficent on data that is almost sorted. Worst case O(n^2), avg.
- n^2/4, Best case O(n). This sort is stable. */
- template<typename T, typename CmpFunc>
- void InsertionSort(T *list, int numItems, CmpFunc &cmp);
- /** Shell sort is an optimization of insertion sort, performs in O(n^1.25) on average.
- Worst case O(n^2). This sort is not stable. */
- template<typename T, typename CmpFunc>
- void ShellSort(T *list, int numItems, CmpFunc &cmp);
- /** Bubble sort sorts in worst case O(n^2) time, best case O(n) if the list is already almost sorted.
- This sort is stable. */
- template<typename T, typename CmpFunc>
- void BubbleSort(T *list, int numItems, CmpFunc &cmp);
- /** Cocktail sort == Bidirectional Bubble sort == Shaker sort == Ripple sort == Shuttle sort:
- Stable optimization of Bubble sort, worst case O(n^2). If the list is mostly ordered,
- then the running time is near O(n). */
- template<typename T, typename CmpFunc>
- void CocktailSort(T *list, int numItems, CmpFunc &cmp);
- /** Comb sort is a "diminishing" Bubble sort, an unstable optimization of Bubble sort.
- Generally performs far better than Bubble/Cocktail sorts. */
- template<typename T, typename CmpFunc>
- void CombSort(T *list, int numItems, CmpFunc &cmp);
- /** Merge sort has constant running time O(n*logn). Requires O(n) of additional space and
- has a recursive call overhead of 2n-1. This sort is stable. Note that this sort dynamically
- allocates memory with a call to new[]. */
- template<typename T, typename CmpFunc>
- void MergeSort(T *list, int numItems, CmpFunc &cmp);
- /** Quicksort sorts in avg. O(n*logn) time, with a O(logn) recursive call overhead. In worst case
- (array is sorted in descending order) degenerates into a selection sort with O(n^2)
- complexity. The middle element of the sublist is chosen as pivot. This sort is not
- stable, and it has a potential security vulnerability due to recursive calls. */
- template<typename T, typename CmpFunc>
- void QuickSort(T *list, int numItems, CmpFunc &cmp);
- /** Heapsort is an in-place working algorithm that runs in O(n*logn) time. Generally
- slower than Quicksort, but is better in worst case scenario when the list is almost sorted.
- This sort is not stable. */
- template<typename T, typename CmpFunc>
- void HeapSort(T *list, int numItems, CmpFunc &cmp);
- /** Introspective sort starts as Quicksort, but switches to Heapsort when the maximum
- number of recursion levels has been exceeded. This shields the implementation against
- stack overflow. If it's known that Introsorting a particular list will cause it to switch
- to Heapsort, it is faster to directly call Heapsort instead. Introsort is not stable. */
- template<typename T, typename CmpFunc>
- void IntroSort(T *list, int numItems, int nMaxRecursionLevels, CmpFunc &cmp);
- /// This can be used for debugging.
- template<typename T, typename CmpFunc>
- bool IsSorted(T *list, int numItems, CmpFunc &cmp);
- // The following lines define shortcuts for easier using when the standard < and == comparison operators are involved:
- template<typename T> void SelectionSort(T *list, int numItems) { SelectionSort<T>(list, numItems, TriCmp<T>); }
- template<typename T> void InsertionSort(T *list, int numItems) { InsertionSort<T>(list, numItems, TriCmp<T>); }
- template<typename T> void ShellSort(T *list, int numItems) { ShellSort<T>(list, numItems, TriCmp<T>); }
- template<typename T> void BubbleSort(T *list, int numItems) { BubbleSort<T>(list, numItems, TriCmp<T>); }
- template<typename T> void CocktailSort(T *list, int numItems) { CocktailSort<T>(list, numItems, TriCmp<T>); }
- template<typename T> void CombSort(T *list, int numItems) { CombSort<T>(list, numItems, TriCmp<T>); }
- template<typename T> void MergeSort(T *list, int numItems) { MergeSort<T>(list, numItems, TriCmp<T>); }
- template<typename T> void QuickSort(T *list, int numItems) { QuickSort<T>(list, numItems, TriCmp<T>); }
- template<typename T> void HeapSort(T *list, int numItems) { HeapSort<T>(list, numItems, TriCmp<T>); }
- template<typename T> void IntroSort(T *list, int numItems, int nMaxRecursionLevels = 1000) { IntroSort<T>(list, numItems, nMaxRecursionLevels, TriCmp<T>); }
- } // ~sort
- } // ~kNet
- #include "Sort.inl"
|