归并排序(Merge sort)是创建在归并操做上的一种有效的排序算法,指的是将两个已经排序的序列合并成一个序列的操做。该算法是采用分治法(Divide and Conquer)的一个很是典型的应用。html
做为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:git
1. 从下往上的归并排序【迭代】:github
经过分治法将长度为n的序列划分为n个长度为1的子序列。 算法
进行两两归并比较,获得 n/2 个长度为 2 的有序子序列 数组
重复第 2 步,直到全部子序列归并成一个长度为 n 的有序序列。数据结构
2. 从上往下的归并排序【递归】:ide
分解 -- 将当前区间一分为二,即求分裂点 mid = (low + high)/2; post
求解 -- 递归地对两个子区间a[low...mid] 和 a[mid+1...high]进行归并排序。递归的终结条件是子区间长度为1。性能
合并 -- 将已排序的两个子区间a[low...mid]和 a[mid+1...high]归并为一个有序的区间a[low...high]。学习
3. 归并步骤:
申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
设定两个指针,最初位置分别为两个已经排序序列的起始位置;
比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
重复步骤 3 直到某一指针达到序列尾;
将另外一序列剩下的全部元素直接复制到合并序列尾。
归并排序的效率是比较高的,设数列长为N,将数列分开成小数列一共要 logN 步,每步都是一个合并有序数列的过程,时间复杂度能够记为O(N),故一共为O(N*logN),故时间复杂度为O(nlogn)。
归并排序过程当中,须要一个辅助空间来暂存两有序子文件归并的结果,所以空间复杂度为O(n)。
归并是稳定的算法,在分解和并归过程当中元素相对顺序未发生改变。
不能归位
public class MergeSort { // 归并排序(从上往下,递归) public static void mergeSortUp2Down(int [] arr, int start, int end){ if(arr!=null && start<end){//当子序列中只有一个元素时结束递归 int mid=(start+end)/2;//划分子序列 mergeSortUp2Down(arr, start, mid);//对左侧子序列进行递归排序 mergeSortUp2Down(arr, mid+1, end);//对右侧子序列进行递归排序 merge(arr, start, mid, end);//合并 } } //归并排序(从下往上,迭代) public static void mergeSortDown2Up(int [] arr){ if(arr!=null){ int len = arr.length; //gap表示有序数组的长度(1,2,4,8……) for(int gap = 1; gap < len; gap*=2){ int i; // 将"每2个相邻的子数组" 进行合并排序。 for(i = 0; i+2*gap-1 < len; i+=(2*gap)){ merge(arr, i, i+gap-1, i+2*gap-1); } // 若 i+gap-1 < len-1,则剩余一个子数组没有配对。 // 将该子数组合并到已排序的数组中。 if (i+gap-1 < len-1){ merge(arr, i, i+gap-1, len-1); } } } } //两路归并算法,两个排好序的子序列合并为一个子序列 public static void merge(int []arr, int left, int mid, int right){ int []tmp=new int[arr.length];//辅助数组 int p1=left,p2=mid+1,k=left;//p一、p2是检测指针,k是存放指针 while(p1<=mid && p2<=right){ if(arr[p1]<=arr[p2]) tmp[k++]=arr[p1++]; else tmp[k++]=arr[p2++]; } while(p1<=mid) tmp[k++]=arr[p1++];//若是第一个序列未检测完,直接将后面全部元素加到合并的序列中 while(p2<=right) tmp[k++]=arr[p2++];//同上 //复制回原素组 for (int i = left; i <=right; i++) arr[i]=tmp[i]; } public static void main(String[] args){ int[] arr = { 49, 38, 65, 97, 76, 13, 27, 50 }; //mergeSortUp2Down(arr, 0, a.length-1); mergeSortDown2Up(arr); System.out.println("排好序的数组:"); for (int e : arr) System.out.print(e+" "); } }