1. 算法介绍
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序是一种稳定的排序方法。
2. 归并操作
归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。 如:
设有数列{6,202,100,301,38,8,1}
初始状态:6,202,100,301,38,8,1
第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;
第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;
第三次归并后:{1,6,8,38,100,202,301},比较次数:4;
总的比较次数为:3+4+4=11;
逆序数为14;
3. 工作原理
归并操作的工作原理如下:
- 第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
- 第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
- 第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
- 重复步骤3直到某一指针超出序列尾
- 将另一序列剩下的所有元素直接复制到合并序列尾
4. 算法实现(java)
4.1 动图展示
4.2 代码实现
public static void main(String[] args) {
int arr[] = {3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};
System.out.println("排序前");
printArr(arr);
mergeSort(arr);
System.out.println("排序后");
printArr(arr);
}
public static void mergeSort(int[] arr) {
sort(arr, 0, arr.length - 1);
}
//递归
public static void sort(int[] arr, int start, int end) {
if (start >= end)
return;
// 找出中间索引
int mid = (start + end) / 2;
// 对左边数组进行递归
sort(arr, start, mid);
// 对右边数组进行递归
sort(arr, mid + 1, end);
// 合并
merge(arr, start, mid, end);
}
// 将两个数组进行归并,归并前面2个数组已有序,归并后依然有序
public static void merge(int[] arr, int start, int mid, int end) {
int[] temp = new int[arr.length];// 临时数组
int k = 0;
int i = start;
int j = mid + 1;
while (i <= mid && j <= end) {
// 从两个数组中取出较小的放入临时数组
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
// 剩余部分依次放入临时数组(实际上两个while只会执行其中一个)
while (i <= mid) {
temp[k++] = arr[i++];
}
while (j <= end) {
temp[k++] = arr[j++];
}
// 将临时数组中的内容拷贝回原数组中 (left-right范围的内容)
for (int m = 0; m < k; m++) {
arr[m + start] = temp[m];
}
}
private static void printArr(int[] arr) {
for (Object o : arr) {
System.out.print(o);
System.out.print(" ");
}
System.out.println();
}
5.算法分析
- 稳定性
归并排序是一种稳定的排序。
- 存储结构要求
可用顺序存储结构。也易于在链表上实现。
- 时间复杂度
对长度为n的文件,需进行 趟二路归并,每趟归并的时间为O(n),故其时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlgn)。
- 空间复杂度
需要一个辅助向量来暂存两有序子文件归并的结果,故其辅助空间复杂度为O(n),显然它不是就地排序。
6 总结
归并排序虽然比较稳定,在时间上也是非常有效的,但是这种算法很消耗空间,一般来说只有在外部排序才会采用这个方法,但在内部排序不会用这种方法,而是用快速排序。