“这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战”
关注我,以下内容持续更新
归并排序的介绍
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。归并排序,首先把一个数组中的元素,依次折半拆分,直至无法拆分,再按照正确的顺序两两合并为有序的子序列,然后再把有序的子序列继续两两合并,直至最后一次合并,得到一个完全有序的序列。所以归并排序的思想是逐步将已有序的子序列合并,得到完全有序的序列。(将两个有序表合并成一个有序表,称为二路归并。)
归并排序其实要做两件事:分解和合并
(1)“分解”——将序列每次折半划分。
(2)“合并”——将划分后的序列段两两合并后排序。
(1) 分治图解
(2) 单趟合并图解
例如要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8]
归并排序有两种实现方式:基于递归的归并排序和基于循环的归并排序(也叫自顶向下的归并排序和自底向上的归并排序)。无论是基于递归还是循环的归并排序,它们调用的核心方法都是相同的:完成一趟合并的算法,即两个已经有序的数组序列合并成一个更大的有序数组序列。
归并排序的递归实现
基于递归的归并排序又叫做自顶向下的归并排序。
原理:使用递归方法来实现归并排序时,核心思想是两个有序子序列的合并,注意这里是有序子序列的合并,因此下面要做两件事,整个过程如下图所示:
(1)将待排序序列从中间一分为二,对左右两边再进行递归分割操作,得到n个相互独立的子序列; (2)对n个独立的子序列递归的执行合并操作,最终得到有序的序列。
//归并排序的递归实现
-(NSArray*)mergeSort:(NSArray*)arr{
if (arr.count<=1) {//递归停止条件
return [arr mutableCopy];
}
//1. 把数组从中间分成左右两部分
int center = (int)arr.count/2;
NSArray*left = [arr subarrayWithRange:NSMakeRange(0, center)];
NSArray*right = [arr subarrayWithRange:NSMakeRange(center, arr.count-center)];
//2.分别对对左右两半部分进行递归
NSArray*leftSub = [self mergeSort:left];
NSArray*rightSub = [self mergeSort:right];
//3.合并
return [self mergeLeft:leftSub right:rightSub];
}
//合并的逻辑
-(NSArray*)mergeLeft:(NSArray*)left right:(NSArray*)right{
NSMutableArray*result = [NSMutableArray array];
int i = 0;
int j = 0;
while (i<left.count && j<right.count) {
if ([left[i] intValue] < [right[j] intValue]) {
[result addObject:left[i]];
i++;
}else {
[result addObject:right[j]];
j++;
}
}
while (i<left.count) {
[result addObject:left[i]];
i++;
}
while (j<right.count) {
[result addObject:right[j]];
j++;
}
return result.copy;
}
递归的终止条件为子序列的长度为1,因为元素为1个默认是有序的
核心代码如下:
//2.分别对左右两半部分进行递归
NSArray*leftSub = [self mergeSort:left];
NSArray*rightSub = [self mergeSort:right];
//3.合并
return [self mergeLeft:leftSub right:rightSub];
递归方法的不足:每一步合并都必须创建一个临时数组,此数组用来暂存已经排好序的子序列,直到序列完全排好序。整个归并排序过程中的空间复杂度为O(n)。
归并排序的性能
归并排序是稳定排序,它也是一种十分高效的排序,它利用完全二叉树特性。 归并排序的最好、最坏和平均时间复杂度都是O(nlog2n),空间复杂度是 O(n)。