BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / acm-icpc / #91791同步于 2016/12/5
该镜像源已超过 30 天没有更新,可能在源站已被删除。
ACM_ICPC机器人发帖

【讨论】更高效的 MergeSort

Insane
2016/12/5镜像同步5 回复
## 0. 简介 本文简要介绍一下比传统MergeSort更高效的算法,在原来的算法Merge基础上,少发生一半拷贝。欢迎探讨,感谢阅读。 原文链接如下:http://loverszhaokai.com/posts/More-Efficient-MergeSort/ ## 1. Reference [原文链接](http://loverszhaokai.com/posts/More-Efficient-MergeSort/) [Introuction to Algorithms](http://faculty.mu.edu.sa/public/uploads/1360957074.1109Introduction_to_Algorithms_Third_Edition.pdf) [https://github.com/loverszhaokai/ALG/blob/master/src/sort.cc](https://github.com/loverszhaokai/ALG/blob/master/src/sort.cc) ## 2. MergeSort ```c++ void merge(int a[], int b[], const int left, const int middle, const int right) { int li, ri, i; li = left; ri = middle + 1; i = 0; while (li <= middle && ri <= right) { if (a[li] < a[ri]) b[i++] = a[li++]; else b[i++] = a[ri++]; } while (li <= middle) b[i++] = a[li++]; while (ri <= right) b[i++] = a[ri++]; } void copy(int dst[], int dleft, int src[], int sleft, int sright) { memcpy(dst + dleft, src + sleft, sizeof(int) * (sright - sleft + 1)); } void _merge_sort(int a[], int b[], const int left, const int right) { if (left >= right) return; int middle = (left + right) / 2; _merge_sort(a, b, left, middle); _merge_sort(a, b, middle + 1, right); merge(a, b, left, middle, right); copy(a, left, b, 0, right - left); } void merge_sort(int a[], const int size) { int *b = (int *)malloc(size * sizeof(int)); _merge_sort(a, b, 0, size - 1); free(b); } ``` ## 3. More Efficient MergeSort We can save some time by copy half when `merge()`. In `merge()`, we copy from **left** to **right**, but in `MergeKai()` we can only copy from **left** to **middle**. The `merge()` has `NlgN` duplications which the `MergeKai()` has `1/2 * NlgN` duplications. http://loverszhaokai.com/images/2016120501.png normal merge sort http://loverszhaokai.com/images/2016120502.png more efficient merge sort Just as the previous example, the efficient merge sort does not need to copy `1, 3, 7, 8` to the assit array. ```c++ // Merge the two list in [left, mid], and (mid, right]. Then, write // the result to [left, right] static void MergeKai(int a[], int assist[], const int left, const int mid, const int right) { int l = left; int r = mid + 1; int assist_index = 0; // Copy [left, mid] to assit[0, mid - left] memcpy(assist, a + left, (mid - left + 1) * sizeof(int)); while (assist_index <= mid - left && r <= right) { if (assist[assist_index] <= a[r]) { a[l++] = assist[assist_index++]; continue; } else if (assist[assist_index] > a[r]) { a[l++] = a[r++]; } } while (assist_index <= mid - left) { a[l++] = assist[assist_index++]; } while (r <= right) { a[l++] = a[r++]; } } static void MergeSortKaiImpl(int a[], int assist[], const int left, const int right) { if (left >= right) { return; } const int mid = (left + right) / 2; MergeSortKaiImpl(a, assist, left, mid); MergeSortKaiImpl(a, assist, mid + 1, right); MergeKai(a, assist, left, mid, right); } void MergeSortKai(int a[], const int size) { int* assist= (int *)malloc(size * sizeof(int)); MergeSortKaiImpl(a, assist, 0, size - 1); free(assist); } ``` ## 4. Experiments source: [https://github.com/loverszhaokai/ALG/blob/master/src/sort.cc](https://github.com/loverszhaokai/ALG/blob/master/src/sort.cc) [https://github.com/loverszhaokai/ALG/blob/master/test/sort_test.cc](https://github.com/loverszhaokai/ALG/blob/master/test/sort_test.cc) result: ``` It takes 1524.61 ms to generate arrays: 1000000 * 20 Sort Function Total Run Time Array Size --------------------------------------------------------------------- merge_sort_iteratively 826 ms 1000000 * 20 merge_sort 840 ms 1000000 * 20 MergeSortIterativelyKai 826 ms 1000000 * 20 MergeSortKai 809 ms 1000000 * 20 It takes 15028.2 ms to generate arrays: 10000000 * 20 Sort Function Total Run Time Array Size --------------------------------------------------------------------- merge_sort_iteratively 8717 ms 10000000 * 20 merge_sort 8820 ms 10000000 * 20 MergeSortIterativelyKai 8425 ms 10000000 * 20 MergeSortKai 8389 ms 10000000 * 20 It takes 1929.31 ms to generate arrays: 100000 * 200 Sort Function Total Run Time Array Size --------------------------------------------------------------------- merge_sort_iteratively 1245 ms 100000 * 200 merge_sort 1347 ms 100000 * 200 MergeSortIterativelyKai 1246 ms 100000 * 200 MergeSortKai 1275 ms 100000 * 200 ```
订阅后,新回复会通过你的通知中心匿名送达。
5 条回复
henceman机器人#1 · 2016/12/6
经典算法的讨论应该加上应用场景吧,看标题会吓一跳的。。。复杂度的问题数学上应该早就可以证明,而不会直到今天才被人提出“更高效”的算法吧
aquamarine机器人#2 · 2016/12/6
和STL的StableSort比一发。 你要比STL的快,我们可以再讨论一下。
wk1948机器人#3 · 2016/12/6
然而有种东西叫in place mergesort http://blog.csdn.net/acaiwlj/article/details/10948035
Insane机器人#4 · 2016/12/6
这个算法虽然空间复杂度是O(1),但是该算法发生的拷贝次数更多,实际效率更低,而且低的可怕。 实现直接拷贝的博客中的代码,实验对比数据如下: https://github.com/loverszhaokai/ALG/blob/master/src/merge_sort_o1_space.cc ```c++ It takes 24928.3 ms to generate arrays: 100000 * 2000 Sort Function Total Run Time Array Size ------------------------------------------------------------------------------ merge_sort_iteratively 17768 ms 100000 * 2000 merge_sort 18605 ms 100000 * 2000 merge_sort_kai 18493 ms 100000 * 2000 MergeSortIterativelyKai 17157 ms 100000 * 2000 MergeSortKai 18751 ms 100000 * 2000 MergeSortO1Space 195738 ms 100000 * 2000 /home/zhaokai/WorkSpace/ALG/ALG/test/sort_test.cc total run time = 314778 ms ``` #### 这个种O1空间复杂度实现的MergeSort()应该是用处不大吧,但是思路挺有意思的。 【 在 wk1948 的大作中提到: 】 : 然而有种东西叫in place mergesort : http://blog.csdn.net/acaiwlj/article/details/10948035
fty机器人#5 · 2016/12/6
排版很舒服,lz的对照组应该拿STL等库做吧,不仅仅是自己写的对照。。