算法笔记练习 4.6 two pointers 问题 B: 基础排序III:归并排序
题目
题目描述
归并排序是一个时间复杂度为O(nlogn)的算法,对于大量数据远远优于冒泡排序与插入排序。
这是一道排序练习题,数据量较大,请使用归并排序完成。
输入
第一行一个数字n,代表输入的组数
其后每组第一行输入一个数字m,代表待排序数字的个数
其后m行每行一个数据,大小在1~100000之间,互不相等,最多有10万个数据。
输出
升序输出排好序的数据,每行一个数字
样例输入
1
10
10
9
8
7
6
5
4
3
2
1
样例输出
1
2
3
4
5
6
7
8
9
10
思路
思路参考算法笔记P141。
注意:mergeSort
的写法和书上有微小的差异,改成了数组下标从 0 开始的写法,有两处改动:
for (i = 0; i < n; i += step)
,原本是<=
if (middle + 1 < n)
,原本是<=
,这里一开始没注意到,debug 了很久。
思考:
- 相比较归并排序的递归写法,从写代码的角度来看,递归写法是自顶向下的,而迭代写法更符合程序实际运行时的“归并”情况;
- 迭代写法在每次合并前要判断右子区间是否存在元素,这个判断实际上就是递归写法里的递归边界。
代码
#include <stdio.h>
int min(int a, int b){
return a < b ? a : b;
}
// 把数组 a 中分别递增的两半合并
void merge(int *a, int L1, int R1, int L2, int R2) {
int temp[R2 - L1 + 1];
int *ptemp = temp;
int *pa = a + L1;
int *pb = a + L2;
while(pa <= a + R1 && pb <= a + R2) {
if (*pa <= *pb)
*ptemp++ = *pa++;
else
*ptemp++ = *pb++;
}
while (pa <= a + R1)
*ptemp++ = *pa++;
while (pb <= a + R2)
*ptemp++ = *pb++;
int i;
for (i = 0; i < R2 - L1 + 1; ++i)
a[L1 + i] = temp[i];
}
// 二路归并排序,迭代写法
void mergeSort(int n, int *a) {
if (n < 2)
return;
int step;
for (step = 2; step / 2 <= n; step *= 2) {
int i;
for (i = 0; i < n; i += step) {
int middle = i + step / 2 - 1;
if (middle + 1 < n)
merge(a, i, middle, middle + 1, min(i + step - 1, n));
}
}
}
int main(){
int n, m;
while (scanf("%d", &n) != EOF) {
while (n--) {
scanf("%d", &m);
int nums[m], i;
for (i = 0; i < m; ++i)
scanf("%d", &nums[i]);
mergeSort(m, nums);
for (i = 0; i < m; ++i)
printf("%d\n", nums[i]);
}
}
return 0;
}