归并排序(Selection Sort)-Java常见经典算法详解

归并排序(Merge Sort)算法简介:

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治策略(Divide and Conquer)(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序是一种稳定的排序方法。

归并排序(Merge Sort)算法原理:

 可以看到这种结构很像一棵完全二叉树,本文的归并排序我们采用递归去实现(也可采用迭代的方式去实现)。阶段可以理解为就是递归拆分子序列的过程,递归深度为log2(n)。

合并相邻有序子序列:

再来看看阶段,我们需要将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],来看下实现步骤。

归并排序(Merge Sort)代码实现:

import java.util.Arrays;
public class Demo {
	    public static void main(String[] args){
	        int []arr = {9,8,7,6,5,4,3,2,1};
	        System.out.println("排序前:"+Arrays.toString(arr));
	        sort(arr);
	        System.out.println("排序前:"+Arrays.toString(arr));
	    }
	    public static void sort(int[] array){
	        int []temp = new int[array.length];//在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间
	        sort(array,0,array.length-1,temp);
	    }
	    private static void sort(int[] array,int left,int right,int[] temp){
	        if(left<right){
	            int mid = (left+right)/2;
	            sort(array,left,mid,temp);//左边归并排序,使得左子序列有序
	            sort(array,mid+1,right,temp);//右边归并排序,使得右子序列有序
	            mergeSort(array,left,mid,right,temp);//将两个有序子数组合并操作
	        }
	    }
	    private static void mergeSort(int[] array,int left,int mid,int right,int[] temp){
	        int i = left;//左序列指针
	        int j = mid+1;//右序列指针
	        int t = 0;//临时数组指针
	        while (i<=mid && j<=right){
	            if(array[i]<=array[j]){
	                temp[t++] = array[i++];
	            }else {
	                temp[t++] = array[j++];
	            }
	        }
	        while(i<=mid){//将左边剩余元素填充进temp中
	            temp[t++] = array[i++];
	        }
	        while(j<=right){//将右序列剩余元素填充进temp中
	            temp[t++] = array[j++];
	        }
	        t = 0;
	        //将temp中的元素全部拷贝到原数组中
	        while(left <= right){
	            array[left++] = temp[t++];
	        }
	   }
}

归并排序(Merge Sort)的时间复杂度:

归并排序中,分割序列所花费的时间不算在运行时间内(可以当作序列本来就是分割好的)。在合并两个已排好序的子序列时,只需重复比较首位数据的大小,然后移动较小的数据,因此只需花费和两个子序列的长度相应的运行时间。也就是说,完成一行归并所需的运行时间取决于这-行的数据量。看一下上面的图便能得知,无论哪一行都是n个数据,所以每行的运行时间都为O(n)。
而将长度为n的序列对半分割直到只有一个数据为止时,可以分成log2(n)行,因此,总共有log2(n)行。也就是说,总的运行时间为O(nlogn),这与前面讲到的堆排序相同。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章