Snippets.PRO Keep. Track. Share.

Have a Snippet?

Keep, track and share your code snippets with your friends



C++: Merge sort Share on Vkontakte

Merge sort

  1. *****************************************************************
  2. * File: Mergesort.hh
  3. * Author: Keith Schwarz ()
  4. *
  5. * An implementation of the Mergesort algorithm. This algorithm
  6. * is implemented with a focus on readability and clarity rather
  7. * than speed. Ideally, this should give you a better sense
  8. * for how Mergesort works, which you can then use as a starting
  9. * point for implementing a more optimized version of the algorithm.
  10. *
  11. * In case you are not familiar with Mergesort, the idea behind the
  12. * algorithm is as follows. Given an input list, we wish to sort
  13. * the list from lowest to highest. To do so, we split the list
  14. * in half, recursively sort each half, and then use a merge algorithm
  15. * to combine the two lists back together. As a base case for
  16. * the recursion, a list with zero or one elements in it is trivially
  17. * sorted.
  18. *
  19. * The only tricky part of this algorithm is the merge step, which
  20. * takes the two sorted halves of the list and combines them together
  21. * into a single sorted list. The idea behind this algorithm is
  22. * as follows. Given the two lists, we look at the first element of
  23. * each, remove the smaller of the two, and place it as the first
  24. * element of the overall sorted sequence. We then repeat this
  25. * process to find the second element, then the third, etc. For
  26. * example, given the lists 1 2 5 8 and 3 4 7 9, the merge
  27. * step would work as follows:
  28. *
  29. * FIRST LIST SECOND LIST OUTPUT
  30. * 1 2 5 8 3 4 7 9
  31. *
  32. * FIRST LIST SECOND LIST OUTPUT
  33. * 2 5 8 3 4 7 9 1
  34. *
  35. * FIRST LIST SECOND LIST OUTPUT
  36. * 5 8 3 4 7 9 1 2
  37. *
  38. * FIRST LIST SECOND LIST OUTPUT
  39. * 5 8 4 7 9 1 2 3
  40. *
  41. * FIRST LIST SECOND LIST OUTPUT
  42. * 5 8 7 9 1 2 3 4
  43. *
  44. * FIRST LIST SECOND LIST OUTPUT
  45. * 8 7 9 1 2 3 4 5
  46. *
  47. * FIRST LIST SECOND LIST OUTPUT
  48. * 8 9 1 2 3 4 5 7
  49. *
  50. * FIRST LIST SECOND LIST OUTPUT
  51. * 9 1 2 3 4 5 7 8
  52. *
  53. * FIRST LIST SECOND LIST OUTPUT
  54. * 1 2 3 4 5 7 8 9
  55. *
  56. * The merge step runs in time O(N), and so using the Master Theorem
  57. * Mergesort can be shown to run in O(N lg N), which is asymptotically
  58. * optimal for a comparison sort.
  59. *
  60. * Our implementation sorts elements stored in std::vectors, since
  61. * it abstracts away from the complexity of the memory management for
  62. * allocating the scratch arrays.
  63. */
  64. #ifndef Mergesort_Included
  65. #define Mergesort_Included
  66. #include
  67. #include
  68. /**
  69. * Function: Mergesort(vector& elems);
  70. * Usage: Mergesort(myVector);
  71. * ---------------------------------------------------
  72. * Applies the Mergesort algorithm to sort an array in
  73. * ascending order.
  74. */
  75. template
  76. void Mergesort(std::vector& elems);
  77. /**
  78. * Function: Mergesort(vector& elems, Comparator comp);
  79. * Usage: Mergesort(myVector, std::greater());
  80. * ---------------------------------------------------
  81. * Applies the Mergesort algorithm to sort an array in
  82. * ascending order according to the specified
  83. * comparison object. The comparator comp should take
  84. * in two objects of type T and return true if the first
  85. * argument is strictly less than the second.
  86. */
  87. template
  88. void Mergesort(std::vector& elems, Comparator comp);
  89. /* * * * * Implementation Below This Point * * * * */
  90. /* We store all of the helper functions in this detail namespace to avoid cluttering
  91. * the default namespace with implementation details.
  92. */
  93. namespace detail {
  94. /* Given vectors 'one' and 'two' sorted in ascending order according to comparator
  95. * comp, returns the sorted sequence formed by merging the two sequences.
  96. */
  97. template
  98. std::vector Merge(const std::vector& one, const std::vector& two, Comparator comp) {
  99. /* We will maintain two indices into the sorted vectors corresponding to
  100. * where the next unchosen element of each list is. Whenever we pick
  101. * one of the elements from the list, we'll bump its corresponding index
  102. * up by one.
  103. */
  104. size_t onePos = 0, twoPos = 0;
  105. /* The resulting vector. */
  106. std::vector result;
  107. /* For efficiency's sake, reserve space in the result vector to hold all of
  108. * the elements in the two vectors. To be truly efficient, we should probably
  109. * take in as another parameter an existing vector to write to, but doing so
  110. * would complicate this implementation unnecessarily.
  111. */
  112. result.reserve(one.size() + two.size());
  113. /* The main loop of this algorithm continuously polls the first and second
  114. * list for the next value, putting the smaller of the two into the output
  115. * list. This loop stops once one of the lists is completely exhausted
  116. * so that we don't try reading off the end of one of the lists.
  117. */
  118. while (onePos < one.size() && twoPos < two.size()) {
  119. /* If the first element of list one is less than the first element of
  120. * list two, put it into the output sequence.
  121. */
  122. if (comp(one[onePos], two[twoPos])) {
  123. result.push_back(one[onePos]);
  124. /* Also bump onePos since we just consumed the element at that
  125. * position.
  126. */
  127. ++onePos;
  128. }
  129. /* Otherwise, either the two are equal or the second element is smaller
  130. * than the first. In either case, put the first element of the second
  131. * sequence into the result.
  132. */
  133. else {
  134. result.push_back(two[twoPos]);
  135. ++twoPos;
  136. }
  137. }
  138. /* At this point, one of the sequences has been exhausted. We should
  139. * therefore put whatever is left of the other sequence into the
  140. * output sequence. We do this by having two loops which consume the
  141. * rest of both sequences, putting the elements into the result. Of these
  142. * two loops, only one will execute, although it isn't immediately
  143. * obvious from the code itself.
  144. */
  145. for (; onePos < one.size(); ++onePos)
  146. result.push_back(one[onePos]);
  147. for (; twoPos < two.size(); ++twoPos)
  148. result.push_back(two[twoPos]);
  149. /* We now have merged all of the elements together, so we can safely
  150. * return the resulting sequence.
  151. */
  152. return result;
  153. }
  154. }
  155. /* Implementation of Mergesort itself. */
  156. template
  157. void Mergesort(std::vector& elems, Comparator comp) {
  158. /* If the sequence has fewer than two elements, it is trivially in sorted
  159. * order and we can return without any more processing.
  160. */
  161. if (elems.size() < 2)
  162. return;
  163. /* Break the list into a left and right sublist. */
  164. std::vector left, right;
  165. /* The left half are elements [0, elems.size() / 2). */
  166. for (size_t i = 0; i < elems.size() / 2; ++i)
  167. left.push_back(elems[i]);
  168. /* The right half are the elements [elems.size() / 2, elems.size()). */
  169. for (size_t i = elems.size() / 2; i < elems.size(); ++i)
  170. right.push_back(elems[i]);
  171. /* Mergesort each half. */
  172. Mergesort(left, comp);
  173. Mergesort(right, comp);
  174. /* Merge the two halves together. */
  175. elems = detail::Merge(left, right, comp);
  176. }
  177. /* The Mergesort implementation that does not require a comparator is implemented
  178. * in terms of the Mergesort that does use a comparator by passing in std::less.
  179. */
  180. template
  181. void Mergesort(std::vector& elems) {
  182. Mergesort(elems, std::less());
  183. }
  184. #endif


Tag: C++, Merge Sort, Algorithm

0 Comments