老生常谈——分治法与归并排序
来源:互联网 发布:mac air app 编辑:程序博客网 时间:2024/06/06 00:52
首先来决一个基本的问题:如何合并两个有序序列?
同样,我们也采取图形演示的方法,来一步一步解决问题,假设我们现在存在两个有序序列:1,3,5和2,4,6,7.
那么我们首先应该在脑海中画出这样的一副图形:
到现在,我们已经有解决问题的思路了:
比较这两个序列的第一个元素,谁较小就输出谁,,然后将较小的元素从原队列删除.如此往下进行,如果某个队列为空,则直接将另一个队列中元素依序输出就好.
按照上面的思路,整个过程用图形演示:
1. 选取较小元素
2. 选取较小元素
3. 选取较小元素
4. 选取较小元素
5. 选取较小元素,此时队列arr1已经为空了,因此后面只需要依次输出arr2中的元素即可
6. 输出元素
7. 输出元素
到现在整个过程已经描述清楚了.在具体的代码实现过程中,删除操作可以用移动下标来实现(许多操作,其实换个角度来想的)
代码实现为:
public static void merge(int[] arr, int start, int mid, int end, int[] temp) { int m = mid; int n = end; int i = start; int j = mid + 1; int z = 0; while (i <= m && j <= n) { if (arr[i] < arr[j]) { temp[z++] = arr[i++]; } else { temp[z++] = arr[j++]; } } while (i <= m) { temp[z++] = arr[i++]; } while (j <= n) { temp[z++] = arr[j++]; } for (i = 0; i < z; i++) arr[start + i] = temp[i]; }
现在我们来总结一下:两个有序队列可以很容易的合并成一个有序队列,合并的效率也是比较高的,可以达到O(n).
反向思考一下,任何一个序列(n>1)都可以被拆分成两个子序列,如果这两个子序列是有序的,那么可以很容易的将这两个子序列合并成有序序列。
ok,现在我们来回忆一下分治法:
把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。
结合我们刚才思考的,我们可以设想:任何一个序列(n>1),都可以不断的被一分为二,直到最后的序列中只有一个元素,只有一个元素的序列当然是有序的。
现在我们已经有一种排序的新思路了:为了让原始序列arr有序,可将它分成A,B两个序列,为让A,B两个序列有序,可以继续将A序列拆成A1,A2两个序列,如此拆分下去,直到序列中只有一个元素。对于B序列也是同样的操作。拆分完毕之后,再合并相近的两个序列就行。
恭喜你,一步一步找到一种排序的新思路——归并排序。现在我们要做的就是通过递归分解数列,然后通过合并就可以完成归并排序了。
实现代码如下:
public class MergeSort { public static void main(String[] args) { int[] arr3 = {1, 2, 5, 4}; int[] temp = new int[arr3.length]; sort(arr3, 0, arr3.length - 1, temp); for (int i = 0; i < temp.length; i++) { System.out.print(temp[i] + " "); } } public static void sort(int[] arr1, int start, int end, int[] temp) { if (start < end) { int mid = (start + end) / 2; System.out.println("mid " + mid + " " + start + ">" + mid + "---" + (mid + 1) + ">" + end); sort(arr1, start, mid, temp); sort(arr1, mid + 1, end, temp); merge(arr1, start, mid, end, temp); } } public static void merge(int[] arr, int start, int mid, int end, int[] temp) { int m = mid; int n = end; int i = start; int j = mid + 1; int z = 0; while (i <= m && j <= n) { if (arr[i] < arr[j]) { temp[z++] = arr[i++]; } else { temp[z++] = arr[j++]; } } while (i <= m) { temp[z++] = arr[i++]; } while (j <= n) { temp[z++] = arr[j++]; } for (i = 0; i < z; i++) arr[start + i] = temp[i]; }}
- 老生常谈——分治法与归并排序
- 分治法—归并排序
- 递归与分治——归并排序
- 分治法与归并排序
- 分治法与归并排序
- 分治法——归并排序
- 分治法算法——归并排序
- 分治法——归并排序
- 分治算法——归并排序与快速排序
- 分治归并——排序
- 分治——归并排序
- 分治策略—归并排序
- 递归与分治:归并排序法
- 分治法,归并排序
- 分治法-归并排序
- 分治法-归并排序
- 归并排序-分治法
- 分治法 - 归并排序
- 第三篇 隐式Intent(同一应用和不同应用之间)
- ionic简介
- junit学习笔记
- Android 框架之创建设备节点文件
- 设计模式学习(一)
- 老生常谈——分治法与归并排序
- 二分图(Java)
- 【POJ 3083】Children of the Candy Corn
- 对于linux下system()函数的深度理解(整理)
- Facebook前端框架React.js JSX语法基础
- 关于sd卡中storage/emulated/0找不到问题
- STL list
- Android Studio初接触
- 动态链接库和静态链接库的原理及区别