第一步:分组
第1层分成2个大组,每组n/2个元素;
第2层分成4个小组,每组n/4个元素;
第3层分成8个更小的组,每组n/8个元素;
一直到每组只有一个元素。
第二步:归并
当每个小组内部比较出先后顺序以后,小组之间会展开进一步的比较和排序,合并成一个大组;大组之间继续比较和排序,再合并成更大的组…最终,所有元素合并成了一个有序的集合。
归并操作
把两个有序的小集合,归并成一个有序的大集合
这正是归并排序的核心所在,需要三个步骤
第一步
创建一个额外的大集合,用于存储归并结果,长度是两个小集合之和。
p1,p2,p是三个辅助指针,用于记录当前操作的位置
第二步
从左到右逐一比较两个小集合中的元素,把较小的元素优先放入大集合。
第三步
从另一个还有剩余元素的集合中,把剩余元素按顺序复制到大集合尾部。
JAVA实现
先划分,然后排序
public static void myMergeSort(int[] array,int start,int end){
//把数组拆分为俩个,分别递归,直到划分为1个单位(start<end来判断)。
System.out.println("现在的起点是: "+start+"终点是: "+end);
if(start<end){
int mid = (start+end)/2;
myMergeSort(array,start,mid);
myMergeSort(array,mid+1,end);
merge(array,start,mid,end);
}
}
具体排序的代码:
private static void merge(int[]array,int start,int mid,int end){
System.out.println("开始排序");
int[] tempArray = new int[end-start+1];
int p1 = start;//左边数组的头指针
int p2 = mid+1;//右边数组的头指针
int p0 = 0;//大数组的头指针
//比较小数组的值,依次放入
while ((p1<=mid)&&(p2<=end)){
if(array[p1]<=array[p2]){
tempArray[p0++]=array[p1++];
}else {
tempArray[p0++]=array[p2++];
}
}
//到这里有一侧的数组放完了,但可能还有一侧数组没放完
//左侧数组没完
while (p1<=mid){
tempArray[p0++] = array[p1++];
}
//右侧数组没完
while (p2<=end){
tempArray[p0++] = array[p2++];
}
//在把大集合赋值回去原来的数组
//array[i+start]= tempArray[i];的原因是: 原来是start是从数组中随机截取的。。。
//i+start中的start相当于偏移量。。。
for (int i =0;i<tempArray.length;i++){
array[i+start]= tempArray[i];
}
}
测试方法:
public static void main(String[] args) {
int [] array = new int[]{5,8,6,3,9,2,1,7};
myMergeSort(array,0,array.length-1);
System.out.println(Arrays.toString(array));
}
这个打印结果可以清楚的看出调用栈的顺序。注意体会。。。。
总结
时间复杂度:O(nlogn)
每一层的运算量:n x 层级数:logn.
空间复杂度:O(n)
单次归并操作开辟的最大空间是n
归并排序是稳定排序