归并排序的基本思想是:将两个(或以上)有序的序列合并成一个新的有序序列。细化来说,归并排序现将长度为n的无序序列看成是n个长度为 1 的有序子序列,首先要做两两合并,得到n/2个长度为2的有序子序列,在做两两合并,……不断重复这个过程,最终得到一个长度为n的有序序列。
对于归并排序而言,关键还是在于合并两个有序子序列。合并算法的具体步骤如下:
1、定义变量 i ,i 从 0 开始,依次等于 A 序列中元素的索引。
2、定义变量 j ,j 从 0 开始,依次等于 B 序列中元素的索引。
3、拿A序列中索引 i 处的元素跟 B序列中 j 索引处的元素进行大小比较,将小的复制到一个临时数组中。
4、如果 i 处索引的值小, i ++;如果 j 索引处的值小,j ++;
重复上面四个过程,即可将A、B俩个序列中的元素复制到临时数组中,直到其中一个数组中的所有元素都被复制到临时数组中,再把另外一个数组中的剩下的元素全部复制到临时数组中,合并即完成,再将临时数组中的元素复制回去即可。
下面是合并操作的实现细节:
归并排序实现:
模拟数据:-56, -21, 56, -21*, 20, 56*, -123, 9, 26, 33
- public class MergeSort {
- public static void mergeSort(DataWrap[] data){
- sort(data, 0, data.length - 1);
- }
- /**
- * 归并排序
- * @param data 待排序的数组元素
- * @param left 待排序的数组段的起始索引
- * @param right 待排序的数组的结束索引
- */
- public static void sort(DataWrap[] data, int left, int right){
- if(left < right){
- int center = (left + right) / 2;
- sort(data, left, center);
- sort(data, center + 1, right);
- merge(data, left, right);
- }
- }
- /**
- * 合并操作
- * @param data 数组对象
- * @param left 左数组的第一个元素索引
- * @param right 右数组的最后一个元素索引
- */
- public static void merge(DataWrap[] data, int left, int right){
- //临时存放比较过后较小的数据项数组
- DataWrap[] tempArr = new DataWrap[data.length];
- int center = (left + right) / 2;
- int mid = center + 1;
- int tempIndex = left;
- int tempStart = left;
- //只要有一组还有数据项没有复制完成就不断地比较复制
- while(left <= center && mid <= right){
- if(data[left].compareTo(data[mid]) <= 0){ //左边小或者相等,这个等 很重要,它关系到归并排序算法的稳定性
- tempArr[tempIndex ++] = data[left ++];
- }else{
- tempArr[tempIndex ++] = data[mid ++];
- }
- }
- //将某一组中还剩的数据项都复制到临时数组中,它可能是左边的也有可能是右边的
- while(left <= center){
- tempArr[tempIndex ++] = data[left ++];
- }
- while(mid <= right){
- tempArr[tempIndex ++] = data[mid ++];
- }
- //将临时数组的left~right数据项复制到data 中
- for(int i = tempStart; i <= right; i ++){
- data[i] = tempArr[i];
- }
- /*while(tempStart <= right){
- data[tempStart] = tempArr[tempStart ++];
- }*/
- }
- public static void main(String[] args){
- DataWrap[] data = {new DataWrap(-56,""),
- new DataWrap(-21,""),
- new DataWrap(56,""),
- new DataWrap(-21,"*"),
- new DataWrap(20,""),
- new DataWrap(56,"*"),
- new DataWrap(-123,""),
- new DataWrap(9,""),
- new DataWrap(26,""),
- new DataWrap(33,"")};
- System.out.println("-排序前-"+java.util.Arrays.toString(data));
- mergeSort(data);
- System.out.println("-排序后-"+java.util.Arrays.toString(data));
- }
- }
从上面的算法实现可以看出,归并排序算法需要递归的进行分解。合并,每进行一趟归并排序需要调用merger()方法一次,每次执行merge()方法需要比较 n 次,一次归并排序算法的时间复杂度为O(N*Log2N) .
但其空间效率较差,它需要一个与原始序列同样大小的辅助序列。
归并排序算法是稳定的。