quicksort.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /*
  2. * Copyright 2002 Adrian Thurston <thurston@cs.queensu.ca>
  3. */
  4. /* This file is part of Aapl.
  5. *
  6. * Aapl is free software; you can redistribute it and/or modify it under the
  7. * terms of the GNU Lesser General Public License as published by the Free
  8. * Software Foundation; either version 2.1 of the License, or (at your option)
  9. * any later version.
  10. *
  11. * Aapl is distributed in the hope that it will be useful, but WITHOUT ANY
  12. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  13. * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
  14. * more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with Aapl; if not, write to the Free Software Foundation, Inc., 59
  18. * Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. */
  20. #ifndef _AAPL_QUICKSORT_H
  21. #define _AAPL_QUICKSORT_H
  22. #include "insertsort.h"
  23. #ifdef AAPL_NAMESPACE
  24. namespace Aapl {
  25. #endif
  26. /**
  27. * \addtogroup sort
  28. * @{
  29. */
  30. /**
  31. * \class QuickSort
  32. * \brief Quick sort an array of data.
  33. *
  34. * QuickSort can be used to sort any array of objects of type T provided a
  35. * compare class is given. QuickSort is in-place. It does not require any
  36. * temporary storage.
  37. *
  38. * Objects are not made aware that they are being moved around in memory.
  39. * Assignment operators, constructors and destructors are never invoked by the
  40. * sort.
  41. *
  42. * QuickSort runs in O(n*log(n)) time in the average case. It is faster than
  43. * mergsort in the average case because it does less moving of data. The
  44. * performance of quicksort depends mostly on the choice of pivot. This
  45. * implementation picks the pivot as the median of first, middle, last. This
  46. * choice of pivot avoids the O(n^2) worst case for input already sorted, but
  47. * it is still possible to encounter the O(n^2) worst case. For example an
  48. * array of identical elements will run in O(n^2)
  49. *
  50. * QuickSort is not a stable sort. Elements with the same key will not have
  51. * their relative ordering preserved. QuickSort switches to an InsertSort
  52. * when the size of the array being sorted is small. This happens when
  53. * directly sorting a small array or when QuickSort calls iteself recursively
  54. * on a small portion of a larger array.
  55. */
  56. /*@}*/
  57. /* QuickSort. */
  58. template <class T, class Compare> class QuickSort :
  59. public InsertSort<T, Compare>
  60. {
  61. public:
  62. /* Sorting interface routine. */
  63. void sort(T *data, long len);
  64. private:
  65. /* Recursive worker. */
  66. void doSort(T *start, T *end);
  67. T *partition(T *start, T *end);
  68. inline T *median(T *start, T *end);
  69. };
  70. #define _QS_INSERTION_THRESH 16
  71. /* Finds the median of start, middle, end. */
  72. template <class T, class Compare> T *QuickSort<T,Compare>::
  73. median(T *start, T *end)
  74. {
  75. T *pivot, *mid = start + (end-start)/2;
  76. /* CChoose the pivot. */
  77. if ( compare(*start, *mid) < 0 ) {
  78. if ( compare(*mid, *end) < 0 )
  79. pivot = mid;
  80. else if ( compare(*start, *end) < 0 )
  81. pivot = end;
  82. else
  83. pivot = start;
  84. }
  85. else if ( compare(*start, *end) < 0 )
  86. pivot = start;
  87. else if ( compare(*mid, *end) < 0 )
  88. pivot = end;
  89. else
  90. pivot = mid;
  91. return pivot;
  92. }
  93. template <class T, class Compare> T *QuickSort<T,Compare>::
  94. partition(T *start, T *end)
  95. {
  96. /* Use the median of start, middle, end as the pivot. First save
  97. * it off then move the last element to the free spot. */
  98. char pcPivot[sizeof(T)];
  99. T *pivot = median(start, end);
  100. memcpy( pcPivot, pivot, sizeof(T) );
  101. if ( pivot != end )
  102. memcpy( pivot, end, sizeof(T) );
  103. T *first = start-1;
  104. T *last = end;
  105. pivot = (T*) pcPivot;
  106. /* Shuffle element to the correct side of the pivot, ending
  107. * up with the free spot where the pivot will go. */
  108. while ( true ) {
  109. /* Throw one element ahead to the free spot at last. */
  110. while ( true ) {
  111. first += 1;
  112. if ( first == last )
  113. goto done;
  114. if ( compare( *first, *pivot ) > 0 ) {
  115. memcpy(last, first, sizeof(T));
  116. break;
  117. }
  118. }
  119. /* Throw one element back to the free spot at first. */
  120. while ( true ) {
  121. last -= 1;
  122. if ( last == first )
  123. goto done;
  124. if ( compare( *last, *pivot ) < 0 ) {
  125. memcpy(first, last, sizeof(T));
  126. break;
  127. }
  128. }
  129. }
  130. done:
  131. /* Put the pivot into the middle spot for it. */
  132. memcpy( first, pivot, sizeof(T) );
  133. return first;
  134. }
  135. template< class T, class Compare> void QuickSort<T,Compare>::
  136. doSort(T *start, T *end)
  137. {
  138. long len = end - start + 1;
  139. if ( len > _QS_INSERTION_THRESH ) {
  140. /* Use quicksort. */
  141. T *pivot = partition( start, end );
  142. doSort(start, pivot-1);
  143. doSort(pivot+1, end);
  144. }
  145. else if ( len > 1 ) {
  146. /* Array is small, use insertion sort. */
  147. InsertSort<T, Compare>::sort( start, len );
  148. }
  149. }
  150. /**
  151. * \brief Quick sort an array of data.
  152. */
  153. template< class T, class Compare>
  154. void QuickSort<T,Compare>::sort(T *data, long len)
  155. {
  156. /* Call recursive worker. */
  157. doSort(data, data+len-1);
  158. }
  159. #ifdef AAPL_NAMESPACE
  160. }
  161. #endif
  162. #endif /* _AAPL_QUICKSORT_H */