一、归并排序的定义
上篇文章带大家了解了什么是堆排序,这篇文章带大家了解下归并排序,归并排序有两个过程:第一个过程是分组,分组是将数据进行逐层对半分组,第一次分成两个大组,每组n/2个元素,第二次分成四个大组,每组n/4个元素,以此操作直到最后每组元素只有一个元素;第二个过程是合并,合并需要比较元素的大小进行排序,第一次有n/2个操作元素同时进行,第二次有n/4操作元素同时进行操作,以此类推,最后进行两个大数组的比较排序就可得到结果。归并这种思想有点像分布式这种思维,将鸡蛋放在很多篮子里,让很多人同时操作,选出更大的鸡蛋,大大提升了效率。
图像演示:
二、代码实现
static public void mergeSort(int[] array, int start, int end){
if(start < end){
//折半成两个小集合,分别进行递归
int mid=start+(end-start)/2;
mergeSort(array, start, mid);
mergeSort(array, mid+1, end);
//把两个有序小集合,归并成一个大集合
merge(array, start, mid, end);
}
}
static private void merge(int[] array, int start, int mid, int end){
//开辟额外大集合,设置指针
int[] tempArray = new int[end-start+1];
int p1=start, p2=mid+1, p=0;
//比较两个小集合的元素,依次放入大集合
while(p1<=mid && p2<=end){
if(array[p1]<=array[p2])
tempArray[p++]=array[p1++];
else
tempArray[p++]=array[p2++];
}
//左侧小集合还有剩余,依次放入大集合尾部
while(p1<=mid)
tempArray[p++]=array[p1++];
//右侧小集合还有剩余,依次放入大集合尾部
while(p2<=end)
tempArray[p++]=array[p2++];
//把大集合的元素复制回原数组
for (int i=0; i<tempArray.length; i++)
array[i+start]=tempArray[i];
}
三、时间复杂度分析
归并排序的时间复杂度为O(NlogN),主要花费时间在合并的操作中,合并又可以细分为3个步骤,第一步是声明一个大数组用来存储两个小数组元素,第二步将两个小数组的元素按顺序比较,选取较大的元素放入大数组中,第三步是将剩余的元素放入大数组中,整个过程和链表的合并操作非常类似。
四、实际应用
合并排序的特点是稳定的,其他两种快速排序和堆排序就不稳定,所以当需要对很大的数据量进行排序而且要求最后不能改变元素的相对位置,合并排序是首选的。下篇文章将讲解另一个稳定的排序算法:基数排序。
五、表格总结
排序类型 | 时间复杂度 | 空间复杂度 | 稳定性 |
---|---|---|---|
归并排序 | O(NlogN) | O(NlogN) | 稳定 |