一个比较经典的的排序算法
合并排序的由来
归并排序(Merge Sort)是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。发明者约翰·冯·诺伊曼[1]
基本原理
将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且原问题相同。递归地解这些子问题,然后将各子问题的解合并得到原问题的解。
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾[1]
代码实现
递归版本
最重要的就是合并(merge)过程
我们需要两边数组的范围进行合并排序
代码如下
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
| public static void merge(int[] arr, int l, int r, int mid) {
int length = r - l + 1; int[] arrHelp = new int[length]; int index = 0; int right = mid + 1; int left = l;
while (left <= mid && right <= r) { arrHelp[index++] = arr[left] < arr[right] ? arr[left++] : arr[right++]; } while (left <= mid) { arrHelp[index++] = arr[left++]; } while (right <= r) { arrHelp[index++] = arr[right++]; }
for (int i = l; i <= r; i++) { arr[i] = arrHelp[i - l]; }
}
|
递归调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public static void mergeSort(int[] arr, int l, int r) { if (arr.length == 0) return; if (l == r) return;
int mid = l + ((r - l) >> 1); mergeSort(arr, l, mid); mergeSort(arr, mid + 1, r); merge(arr, l, r, mid); }
|
非递归版本(优化空间复杂度)
当然递归的版本空间复杂度不好所以进行优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public static void mergeSort(int[] arr) { int mergeSize = 1; while (mergeSize < arr.length) { int L = 0; while (L < arr.length) { int mid = L + mergeSize - 1; if (mid >= arr.length) break; int R = Math.min(mid + mergeSize, arr.length - 1); merge(arr, L, R, mid); L = R + 1; } if (mergeSize > arr.length / 2) break; mergeSize <<= 1; }
}
|
总结
时间复杂度的函数为
O(N∗log(N))
空间复杂度 即需要一个相同大小的临时数组
O(N)
拷贝的时候可以保证相等是先拷贝左再拷贝右 所以是稳定的排序算法
每日一句
凭君莫话封候事,一将功成万骨枯 ————曹松《己亥岁二首》
参考
- 百度百科