文章内容参考:【排序算法】归并排序原理及Java实现
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
1. 基本思想
归并排序就是利用归并的思想实现的排序方法。而且充分利用了完全二叉树的深度是(log(n) +1)的特性,因此效率比较高。其基本原理如下:对于给定的一组记录,利用递归与分治技术将数据序列划分成为越来越小的半子表,在对半子表排序,最后再用递归方法将排好序的半子表合并成为越来越大的有序序列。
经过第一轮比较后得到最小的记录,然后将该记录的位置与第一个记录的位置交换;接着对不包括第一个记录以外的其他记录进行第二次比较,得到最小记录并与第二个位置记录交换;重复该过程,知道进行比较的记录只剩下一个为止。
2. 复杂度分析
一趟归并需要将数组 a[]中相邻的长度为h的有序序列进行两两归并.并将结果放到temp[]中,这需要将待排序列中的所有记录扫描一遍,因此耗费O(n),而又完全二叉树的深度可知,整个归并排序需要进行(logn)次,因此总的时间复杂度为O(nlogn),而且这是归并排序算法中最好、最坏、平均的时间性能。
由于归并排序在归并过程中需要与原始序列同样数量的存储空间存放归并结果以及递归时深度为logn的栈空间,因此空间复杂度为O(n+logn).
另外,对代码进行仔细研究,发现merge函数中有if (a[i] < a[j]) 的语句,说明它需要两两比较,不存在跳跃,因此归并排序是一种稳定的排序算法。
也就是说,归并排序是一种比较占内存,但却效率高且稳定的算法。
3. 工作原理
(1)申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
(2)设定两个指针,最初位置分别为两个已经排序序列的起始位置
(3)比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
(4)重复步骤3直到某一指针达到序列尾
(5)将另一序列剩下的所有元素直接复制到合并序列尾
4. 归并排序过程
以数组{50,10,90,30,70,40,80,60,20}为例
最后的排序结果:
10,20,30,40,50,60,70,80,90
5. Java代码实现
package com.tanqil.test;
import java.util.Arrays;
/**
* Created by hadoop on 17-8-1.
*/
public class MergeSort {
public static void main(String[] args) {
int a[] = {51, 46, 20, 18, 65, 97, 82, 30, 77, 50};
mergeSort(a, 0, a.length - 1);
System.out.println("排序结果:" + Arrays.toString(a));
}
public static void mergeSort(int[] a, int low, int high) {
int mid = (low + high) / 2;
if (low < high) {
//左排
mergeSort(a, low, mid);
//右排
mergeSort(a, mid + 1, high);
//左右合并
merge(a, low, mid, high);
}
}
public static void merge(int[] a, int low, int mid, int high) {
//声明一个临时数组,用来存放排序好的数据
int[] temp = new int[high - low + 1];
int i = low;
int j = mid + 1;
int k = 0;
//按对应位比较大小
while (i <= mid && j <= high) {
if (a[i] < a[j]) {
temp[k++] = a[i];
i++;
} else {
temp[k++] = a[j];
j++;
}
}
//将左边剩余的数据依次存入临时数组
while (i <= mid)
temp[k++] = a[i++];
//将右边剩余的数据依次存入临时数组
while (j <= high)
temp[k++] = a[j++];
//将排好序的数据存入原数组
for (int n = 0; n < temp.length; n++) {
a[n + low] = temp[n];
}
}
}
6. 用途
排序
速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列。
求逆序对数
具体思路是,在归并的过程中计算每个小区间的逆序对数,进而计算出大区间的逆序对数。