从前面已经讲解了冒泡排序、选择排序、插入排序,快速排序了,本章主要讲解的是归并排序,但愿你们看完可以理解并手写出归并排序快速排序的代码,而后就经过面试了!若是我写得有错误的地方也请你们在评论下指出。html
来源百度百科:面试
归并排序(MERGE-SORT)是创建在归并操做上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个很是典型的应用。将已有序的子序列合并,获得彻底有序的序列;即先使每一个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。算法
过程描述:数组
归并过程为:比较a[i]和b[j]的大小,若a[i]≤b[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;不然将第二个有序表中的元素b[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,而后再将另外一个有序表中剩余的元素复制到r中从下标k到下标t的单元。归并排序的算法咱们一般用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操做合并成有序的区间[s,t]。微信
原理:ide
归并操做的工做原理以下:优化
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列spa
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置debug
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置指针
重复步骤3直到某一指针超出序列尾
将另外一序列剩下的全部元素直接复制到合并序列尾
下面我就来作个小小的总结:
如今我有两个已经排好顺序的数组:int[] arr1 = {2, 7, 8}
和int[] arr2 = {1, 4, 9}
,我还有一个大数组来装载它们int[] arr = new int[6];
那么,我将两个数组的值进行比较,谁的值比较小,谁就放入大数组中!
首先,拿出arr1[0]
和arr2[0]
进行比较,显然是arr2[0]
比较小,所以将arr2[0]
放入大数组中,同时arr2
指针日后一格
因此,如今目前为止arr = {1}
随后,拿arr1[0]
和arr2[1]
进行比较,显然是arr1[0]
比较小,将arr1[0]
放入大数组中,同时arr1
指针日后一格
因此,如今目前为止arr = {1,2}
随后,拿arr1[1]
和arr2[1]
进行比较,显然是arr2[1]
比较小,将arr2[1]
放入大数组中,同时arr2
指针日后一格
因此,如今目前为止arr = {1,2,4}
........
遍历到最后,咱们会将两个已排好序的数组变成一个已排好序的数组arr = {1,2,4,7,8,9}
从上面的演算咱们就直到,归并排序的前提是须要两个已经排好顺序的数组,那每每不会有两个已经排好顺序的数组给咱们的呀**(通常是杂乱无章的一个数组)**,那这个算法是否是很鸡肋的呢??
其实并非的,首先假设题目给出的数组是这样子的:int[] arr = {2, 7, 8, 1, 4, 9};
当咱们要作归并的时候就以arr[3]
也就元素为1的那个地方分开。是而后用一个指针L
指向arr[0]
,一个指针M
指向arr[3]
,用一个指针R
指向arr[5]
(数组最后一位)。有了指针的帮助,咱们就能够将这个数组切割成是两个有序的数组了(操做的方式就能够和上面同样了)
但是上面说了,通常给出的是杂乱无章的一个数组,如今仍是达不到要求。好比给出的是这样一个数组:int[] arrays = {9, 2, 5, 1, 3, 2, 9, 5, 2, 1, 8};
此时,咱们就得用到分治的思想了:
int[] arr = {2, 7, 8, 1, 4, 9};
数组分隔成一份一份的,arr[0]
它是一个有序的"数组",arr[1]
它也是一个有序的"数组",利用指针(L,M,R)又能够像操做两个数组同样进行排序。最终合成{2,7}
.......再不断拆分合并,最后又回到了咱们的arr = {1,2,4,7,8,9}
,所以归并排序是能够排序杂乱无章的数组的这就是咱们的分治法--->将一个大问题分红不少个小问题进行解决,最后从新组合起来
实现步骤:
........
public static void main(String[] args) { int[] arrays = {9, 2, 5, 1, 3, 2, 9, 5, 2, 1, 8}; mergeSort(arrays, 0, arrays.length - 1); System.out.println("公众号:Java3y" + arrays); } /** * 归并排序 * * @param arrays * @param L 指向数组第一个元素 * @param R 指向数组最后一个元素 */ public static void mergeSort(int[] arrays, int L, int R) { //若是只有一个元素,那就不用排序了 if (L == R) { return; } else { //取中间的数,进行拆分 int M = (L + R) / 2; //左边的数不断进行拆分 mergeSort(arrays, L, M); //右边的数不断进行拆分 mergeSort(arrays, M + 1, R); //合并 merge(arrays, L, M + 1, R); } } /** * 合并数组 * * @param arrays * @param L 指向数组第一个元素 * @param M 指向数组分隔的元素 * @param R 指向数组最后的元素 */ public static void merge(int[] arrays, int L, int M, int R) { //左边的数组的大小 int[] leftArray = new int[M - L]; //右边的数组大小 int[] rightArray = new int[R - M + 1]; //往这两个数组填充数据 for (int i = L; i < M; i++) { leftArray[i - L] = arrays[i]; } for (int i = M; i <= R; i++) { rightArray[i - M] = arrays[i]; } int i = 0, j = 0; // arrays数组的第一个元素 int k = L; //比较这两个数组的值,哪一个小,就往数组上放 while (i < leftArray.length && j < rightArray.length) { //谁比较小,谁将元素放入大数组中,移动指针,继续比较下一个 if (leftArray[i] < rightArray[j]) { arrays[k] = leftArray[i]; i++; k++; } else { arrays[k] = rightArray[j]; j++; k++; } } //若是左边的数组还没比较完,右边的数都已经完了,那么将左边的数抄到大数组中(剩下的都是大数字) while (i < leftArray.length) { arrays[k] = leftArray[i]; i++; k++; } //若是右边的数组还没比较完,左边的数都已经完了,那么将右边的数抄到大数组中(剩下的都是大数字) while (j < rightArray.length) { arrays[k] = rightArray[j]; k++; j++; } }
我debug了一下第一次的时候,就能够更容易理解了:
上面的两个步骤不断循环,最后得出有序的数组:
来源:www.cnblogs.com/noKing/p/79…
我这里整理一下要点,有兴趣的同窗可到上面的连接上阅读:
若是文章有错的地方欢迎指正,你们互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同窗,能够关注微信公众号:Java3y