(一)归并排序

归并排序是利用归并的思想实现的排序方法,该算法采用经典的分治策略

可以看出这种结构像一个完全二叉树,递归深度为log2n

 

从上往下的归并排序:它与"从下往上"在排序上是反方向的。它基本包括3步:
① 分解 -- 将当前区间一分为二,即求分裂点 mid = (low + high)/2;
② 求解 -- 递归地对两个子区间a[low...mid] 和 a[mid+1...high]进行归并排序。递归的终结条件是子区间长度为1。
③ 合并 -- 将已排序的两个子区间a[low...mid]和 a[mid+1...high]归并为一个有序的区间a[low...high]。 

public class HelloWorld {
	public static void MergeSort(int[] arr,int low,int high)
	{
		if(low<high)//能再分,就继续将数组分割
		{
			int mid=(low+high)/2;
			
			//low-mid有序,mid+1-high有序
			MergeSort(arr,low,mid);
			MergeSort(arr,mid+1,high);
			
			//将arr low-mid,mid+1-high合并成有序
			Sort(arr,low,mid,high);
		}
	}
	
	public static void Sort(int[] arr,int low,int mid,int high)
	{
		int i=low;//指向low-mid数组的起点
		int j=mid+1;//指向mid+1-high数组的起点
		int[] temp=new int[high-low+1];//为了不破坏arr数组,将数据先放入temp中
		int k=0;//k是此次要存入temp的索引
		
		//将数据从小到大存入到temp数组中
		for(;i<=mid&&j<=high;k++)
		{
			if(arr[i]<=arr[j]) //注意这里是<=,确保了稳定性
			{
				temp[k]=arr[i];
				i++;
			}
			else{
				temp[k]=arr[j];
				j++;
			}
		}
		
		//可能存在 第一个数组的数均大于第二个数组,或者第一个数组数据有剩余
		for(;i<=mid;i++)
		{
			temp[k]=arr[i];
			k++;
		}
		//同理,第二个数组
		for(;j<=high;j++)
		{
			temp[k]=arr[j];
			k++;
		}
		
		//将temp数据放入arr中相应位置
		for(int m=0;m<temp.length;m++)
		{
			arr[low+m]=temp[m];
		}
	}
    public static void main(String []args) {
      int[] arr=new int[]{10,8,100,101};
	  MergeSort(arr,0,arr.length-1);
	  for(int m=0;m<arr.length;m++)
		{
			System.out.println(arr[m]);
		}
    }
}

一、时间复杂度、空间复杂度

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用。归并排序的最好、最坏和平均的时间复杂度均为O(nlogn),空间复杂度为O(n)。归并排序比较占用内存(相对于快排的空间复杂度O(logn)以及堆排序的空间复杂度O(1),其中三者时间复杂度相同),当n比较大的时候,归并排序往往会出内存溢出错误。但却是一种效率高且稳定的算法。
 

二、稳定性

在分解的子列中,有1个或2个元素时,1个元素不会交换,2个元素如果大小相等也不会交换。在序列合并的过程中,如果两个当前元素相等时,我们把处在前面的序列的元素保存在结果序列的前面,所以,归并排序也是稳定的。

 

 

 

参考:https://www.javazhiyin.com/1222.html#m

         http://www.cnblogs.com/skywang12345/p/3602369.html

posted @ 2019-03-04 10:21  测试开发分享站  阅读(147)  评论(0编辑  收藏  举报