1、什么是归并排序?
归并排序是属于分冶法的一种排序方式,归并排序将待排序的元素序列分成两个长度相等的子序列,为每一个子序列排序,然后再将他们合并成一个子序列。合并两个子序列的过程也就是两路归并。
2、时间复杂度和空间复杂度
归并排序是一种稳定的排序算法,一般用于对总体无序,但是各子项相对有序的数列。
归并排序的主要问题在于它需要一个与待排序数组一样大的辅助数组空间,所以空间复杂度为T(n)。
由于归并排序每次划分时两个子序列的长度基本一样,所以归并排序最好、最差和平均时间复杂度都是(nlogn)。
3、算法描述
将原本的待排序的数列不断的分解为两个子序列,直到子序列长度为1时开始合并
利用递归的方式分解数列
创建一个和原数组待排序字段长度一致的新数组,分别遍历字段的前半部分和后半部分取值,取其中较小的值
直到一部分遍历结束,将另一部分剩余的值全部赋予新数组
将新数组复制到原数组的待排序字段
4、java代码实现
public class Test { public static void main(String[] args) { // TODO Auto-generated method stub int[] A = {5,2,4,5,6,2,3,6,7,9}; sort(A,1,9);//第一个5不参加排序 for(int l=0;l<A.length;l++) {//输出数组排序后的内容 System.out.print(A[l]); } } public static void sort(int[] arr,int low,int high) { int mid =(low+high)/2; if(low<high) { sort(arr,low,mid); sort(arr,mid+1,high); merge(arr,low,mid,high); } } public static void merge(int[] arr,int low,int mid, int high) { int i=low; int j = mid+1; //在原算法设计中,是使用了两个新数组,将原数组分成左右两个有序的数组 //然后通过合并两个有序的数组对原数组重新排序 //这里通过数组下标的方式(类似分为了两个数组),并建立排序好的新数组, //最后复制到原数组中 int[] temp=new int[high-low+1]; int k=0;//设置新数组的下标标志位 while(i<=mid&&j<=high) { if(arr[i]<=arr[j]) { temp[k++]=arr[i++]; }else { temp[k++]=arr[j++]; } } //当一个数组添加完毕时,直接添加另一个数组的剩余元素 while(i<=mid) { temp[k++]=arr[i++]; } while(j<=high) { temp[k++]=arr[j++]; } //将新数组复制到原来的数组 for(int z=0;z<temp.length;z++) { arr[low+z]=temp[z]; } } }
5、算法的改进
改进归并排序在归并时先判断前段序列的最大值与后段序列最小值的关系再确定是否进行复制比较。如果前段序列的最大值小于等于后段序列最小值,则说明序列可以直接形成一段有序序列不需要再归并,反之则需要。所以在序列本身有序的情况下时间复杂度可以降至O(n)。
TimSort可以说是归并排序的终极优化版本,主要思想就是检测序列中的天然有序子段(若检测到严格降序子段则翻转序列为升序子段)。在最好情况下无论升序还是降序都可以使时间复杂度降至为O(n),具有很强的自适应性。
最好时间复杂度 | 最坏时间复杂度 | 平均时间复杂度 | 空间复杂度 | 稳定性 | |
传统归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | T(n) | 稳定 |
改进归并排序 |
O(n) | O(nlogn) | O(nlogn) | T(n) | 稳定 |
TimSort | O(n) | O(nlogn) | O(nlogn) | T(n) | 稳定 |