归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
归并排序, 每次的小循环和合并2个有序链表有点类似.
1.把原始数组看成n个小数组组成的,每个小数组都是有序的,
2.相邻的2个数字合并成一个有序数组,
3.相邻的4个数字合并成一个有序数组,
....
最后所有数字合并变成一个有序数组.
- (void)sortAction {
/*
归并排序,和合并2个有序链表有点类似
1.把原始数组看成n个,每个数字都看成有序的,
2.相邻的2个数字合并成一个有序数组,
3.相邻的4个数字合并成一个有序数组,
....
最后所有数字合并变成一个有序数组
*/
const int num = 50000;
int a[num];
for (int i = 0; i<num; i++) {
a[i] = arc4random()%(num*10);
}
// 存放暂时的合并结果
int result[num];
memset(result, 0, sizeof(int)*num);
int step = 1;
while (step<=num) {
// 把a数组按照step分割,每个step内部是有序的,结果放到result中
[self mergeArray:a toTargetArray:result step:step count:num];
step *= 2;
// 如果此时step>num, 说明result中的已经是排好序的了, 再次调用,把result的结果复刻一份到原始数组
[self mergeArray:result toTargetArray:a step:step count:num];
step *= 2;
}
for (int i = 0; i<num; i++) {
printf("%d -> ",a[i]);
}
printf("排序完成\n");
}
/// 把a数组按照step分割,每个step内部是有序的,结果放到result中
- (void)mergeArray:(int [])a toTargetArray:(int [])result step:(int)step count:(int)count {
int i = 0;
// 处理完整的step分组,保证最右边的数字不越界
for (; i+2*step<=count; i+=step*2) {
/// 把数组a中[start,mid) 和 [mid,end) 构成的2个有序数组合并成一个有序数组放到result的[start,end)中
[self __mergeArray:a toTargetArray:result form:i mid:i+step end:i+2*step];
}
// 到这里说明前面的完整组合并完成了, 还剩最后一个尾巴, 尾巴的长度可能是一个完整组,可能不到一个组
if (i+step<count) {
// 还有一个完整的一组, 一个半组, 进行合并成一个组
[self __mergeArray:a toTargetArray:result form:i mid:i+step end:count];
} else {
// 剩下的不够完整的一步了
for (; i<count; i++) {
result[i] = a[i];
}
}
}
/// 把数组a中[start,mid) 和 [mid,end) 构成的2个有序数组合并成一个有序数组放到result的[start,end)中
- (void)__mergeArray:(int [])a toTargetArray:(int [])result form:(int)start mid:(int)mid end:(int)end {
int i = start; //[start,mid) 的下标
int j = mid; // [mid,end) 的下标
int r = start; //result的下标
while (i<mid && j<end) {
if (a[i] <= a[j]) {
result[r] = a[i];
i++;
} else {
result[r] = a[j];
j++;
}
r++;
}
// 到这里说明有一个队列走到了尽头, 不管是哪个队列,都把另一个队列的后续元素追加到result中
for (; i<mid; i++) {
result[r] = a[i];
r++;
}
for (; j<end; j++) {
result[r] = a[j];
r++;
}
}
时间复杂度是, 每次的step是*2的, 需要logN次step的循环, 内循环把2个有序数组合并成一个,需要执行N次, 所以2者相乘, 最终的时间复杂度是O(NLogN). 目前来看效率最好的了.