Non-recursive merge sort with two nested loops - how?
这里的第一个问题,是的,这是一个家庭作业问题。我们的任务是在一个数组上执行合并排序(我对此很熟悉),但在某种程度上,我不确定如何执行。通常我会有一个单独的合并和合并排序函数,并使用这两个函数。不过,听起来他想把一切都用一种方法?我只是希望有人能帮我把事情弄清楚,或者用我能更好理解的话来表达。
从任务开始:
you will need to implement a non-recursive version of merge-sort
algorithm. Arrange two nested loops to accomplish this task. The outer
loop should provide the size of segments for merging. The inner loop
should take care of selecting positions of segments. The inner loop
should start at the left edge and move your segments to the right.
Arrange appropriate values of variables left, middle, right, so that
sorting is accomplished just by iterating the call
merge(a,left,middle,right).
我不想这么含糊,但我真的不明白他在说什么。首先,"外环应该提供段的大小"是什么意思?一个循环如何提供什么?下一句呢?他所说的片段是什么意思?数据?
我不是在请求代码,但是任何伪代码都是非常有用的。
如果有人能解释他的意思,我会感激的。我已经给他发过邮件了,但是已经有几个小时了,我还没有回音。
谢谢您!
这并不难。考虑递归合并:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ / \ split +-+-+-+-+ +-+-+-+-+ | | | | | | | | | | +-+-+-+-+ +-+-+-+-+ / \ / \ split +-+-+ +-+-+ +-+-+ +-+-+ | | | | | | | | | | | | +-+-+ +-+-+ +-+-+ +-+-+ / \ / \ / \ / \ split +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ | | | | | | | | | | | | | | | | +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ \ / \ / \ / \ / merge +-+-+ +-+-+ +-+-+ +-+-+ | | | | | | | | | | | | +-+-+ +-+-+ +-+-+ +-+-+ \ / \ / merge +-+-+-+-+ +-+-+-+-+ | | | | | | | | | | +-+-+-+-+ +-+-+-+-+ \ / merge +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ |
如果你注意到,当你分开的时候,你什么都不做。只需告诉递归函数对数组进行部分排序。对数组进行排序包括首先对两部分进行排序,然后将其合并。所以基本上,你得到的是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ | | | | | | | | | | | | | | | | +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ \ / \ / \ / \ / merge +-+-+ +-+-+ +-+-+ +-+-+ | | | | | | | | | | | | +-+-+ +-+-+ +-+-+ +-+-+ \ / \ / merge +-+-+-+-+ +-+-+-+-+ | | | | | | | | | | +-+-+-+-+ +-+-+-+-+ \ / merge +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ |
从现在开始,这应该是显而易见的。首先将数组2的元素按2合并,然后按4合并,然后按8合并等。这是外部
我不会写代码,因为这是作业。
编辑:内部
想象一下,如果
1 2 3 4 5 6 7 | +-+-+ +-+-+ +-+-+ +-+-+ | | | | | | | | | | | | +-+-+ +-+-+ +-+-+ +-+-+ \ / \ / merge +-+-+-+-+ +-+-+-+-+ | | | | | | | | | | +-+-+-+-+ +-+-+-+-+ |
你会得到一个
现在,如果需要将
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | i = 4: +-+-+-+-+-+-+-+-+ | | | | | | | | | +-+-+-+-+-+-+-+-+ ^ ^ ^ ^ ^ ^ ^ ^ | | | | | | | | / / / / \ \ \ \ (j = 0) (j = 4) | | | | | | | | j | | | j | | | | | | j+i-1 | | | j+i-1 | | j+i/2 | | j+i/2 | j+i/2-1 | j+i/2-1 | | | | | | | | | | | | | | | | \ / \ / \ / \ / v v v v merge merge |
希望这至少有一点清楚。
旁白:如果你真的不知道
1 2 3 4 | for (statement1; condition; statement2) { // processing } |
就像写作
1 2 3 4 5 6 | statement1; while (condition) { // processing statement2; } |
所以,如果你总是写
1 | for (int i = 0; i < 10; ++i) |
它意味着从0开始,当
1 | for (int i = 1; i < 1024; i *= 2) |
(试着理解最终的
下面是我使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | template<class InIt, class OutIt> OutIt mergesort(InIt begin, InIt const end, OutIt o /* auxiliary buffer */) { ptrdiff_t j; for (j = 0; begin != end; ++begin, ++j) { for (ptrdiff_t n = 1; n <= j && j % (n * 2) == 0; n *= 2) { o = std::merge(o - n * 2, o - n, o - n, o, begin - n * 2); o = std::swap_ranges(begin - n * 2, begin, o - n * 2); } *o = *begin; ++o; } --j; for (ptrdiff_t m = 1, n = 1; n <= j; n *= 2) { if (j & n) { o = std::merge(o - (m + n), o - m, o - m, o, o - (m + n)); o = std::swap_ranges(begin - (m + n), begin, o - (m + n)); m += n; } } return o; } |
这里有一个使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | template<class InIt> InIt inplace_mergesort(InIt begin, InIt const end) { ptrdiff_t j; for (j = 0; begin != end; ++begin, ++j) { for (ptrdiff_t n = 1; n <= j && j % (n * 2) == 0; n *= 2) { std::inplace_merge(begin - n * 2, begin - n, begin); } } --j; for (ptrdiff_t m = 1, n = 1; n <= j; n *= 2) { if (j & n) { std::inplace_merge(begin - (m + n), begin - m, begin); m += n; } } return begin; } |
下面是Java实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | public static <T extends Comparable<? super T>> void iterativeMergeSort(T[] seed) { for (int i = 1; i <seed.length; i=i+i) { for (int j = 0; j < seed.length - i; j = j + i+i) { inPlaceMerge(seed, j, j + i-1, Math.min(j+i + i -1, seed.length -1)); } } } public static <T extends Comparable<? super T>> void inPlaceMerge(T[] collection, int low, int mid, int high) { int left = low; int right = mid + 1; if(collection[mid].equals(collection[right])) { return ;//Skip the merge if required } while (left <= mid && right <= high) { // Select from left: no change, just advance left if (collection[left].compareTo(collection[right]) <= 0) { left ++; } else { // Select from right: rotate [left..right] and correct T tmp = collection[right]; // Will move to [left] rotateRight(collection, left, right - left); collection[left] = tmp; // EVERYTHING has moved up by one left ++; right ++; mid ++; } } } |
这是单元测试私有整数[]种子;
1 2 3 4 5 6 7 8 9 10 | @Before public void doBeforeEachTestCase() { this.seed = new Integer[]{4,2,3,1,5,8,7,6}; } @Test public void iterativeMergeSortFirstTest() { ArrayUtils.<Integer>iterativeMergeSort(seed); Integer[] result = new Integer[]{1,2,3,4,5,6,7,8}; assertThat(seed, equalTo(result)); } |
这是C版本的自底向上合并排序(有关更多详细信息,请参阅我的博客@http://dream-e-r.blogspot.com/2014/07/mergesort-arrays-and-lists.html)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | void BottomUpMergesort(int[] a) { int[] temp = new int[a.Length]; for (int runWidth = 1; runWidth < a.Length; runWidth = 2 * runWidth) { for (int eachRunStart = 0; eachRunStart < a.Length; eachRunStart = eachRunStart + 2 * runWidth) { int start = eachRunStart; int mid = eachRunStart + (runWidth - 1); if(mid >= a.Length) { mid = a.Length - 1; } int end = eachRunStart + ((2 * runWidth) - 1); if(end >= a.Length) { end = a.Length - 1; } this.Merge(a, start, mid, end, temp); } for (int i = 0; i < a.Length; i++) { a[i] = temp[i]; } } |
合并定义为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | void Merge(int[] a, int start, int mid, int end, int[] temp) { int i = start, j = mid+1, k = start; while((i<=mid) && (j<=end)) { if(a[i] <= a[j]) { temp[k] = a[i]; i++; } else { temp[k] = a[j]; j++; } k++; } while(i<=mid) { temp[k] = a[i]; i++; k++; } while (j <= end) { temp[k] = a[j]; j++; k++; } Assert.IsTrue(k == end+1); Assert.IsTrue(i == mid+1); Assert.IsTrue(j == end+1); } } |
这里的TopDownMergeSort仅供参考:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | void TopDownMergesort(int[] a, int[] temp, int start, int end) { if(start==end) { //run size of '1' return; } int mid = (start + end) / 2; this.TopDownMergesort(a, temp, start, mid); this.TopDownMergesort(a, temp, mid + 1, end); this.Merge(a, start, mid, end, temp); for(int i = start;i<=end;i++) { a[i] = temp[i]; } } |
单元测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | [TestMethod] public void BottomUpMergesortTests() { int[] a = { 13, 4, 1, 3, 8, 11, 9, 10 }; this.BottomUpMergesort(a); int[] b = { 1, 3, 4, 8, 9, 10, 11, 13 }; Assert.IsTrue(a.Length == b.Length); for (int i = 0; i < a.Length; i++) { Assert.IsTrue(a[i] == b[i]); } List<int> l = new List<int>(); for (int i = 10; i >= 1; i--) { l.Add(i); } var la = l.ToArray(); this.BottomUpMergesort(la); for (int i = 1; i <= 10; i++) { Assert.IsTrue(la[i - 1] == i); } l.Clear(); for (int i = 16; i >= 1; i--) { l.Add(i); } la = l.ToArray(); this.BottomUpMergesort(la); for (int i = 1; i <= l.Count; i++) { Assert.IsTrue(la[i - 1] == i); } } |