归并排序基本思想:
- 确定分界点
m
i
d
mid
mid:
mid = (l + r) / 2
- 递归处理左右两子区间 [ l , m i d ] [l, mid] [l,mid], [ m i d + 1 , r ] [mid + 1, r] [mid+1,r]
- 合并两个有序序列
重点是如何合并两个有序序列:可以设置双指针, i i i指向第一个有序序列的开头、 j j j指向第二个有序序列的开头
- i i i从左往右扫, j j j从右往左扫
- q [ i ] q[i] q[i]和 q [ j ] q[j] q[j]二者取小的放入新的数组 p p p中
- 重复1~2直到 i i i或 j j j到达序列末尾
- 把指针没到末尾的序列放入 p p p中
时间复杂度
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
每层总共
n
n
n个,共
l
o
g
n
logn
logn层
归并排序是稳定的:两个相同大小的数不会改变相对位置
#include <iostream>
using namespace std;
const int N = 100005;
int n, q[N], p[N];
void merge_sort(int q[], int l, int r) {
if (l >= r) return ;
int mid = (l + r) >> 1;
merge_sort(q, l, mid);
merge_sort(q, mid + 1, r);
int k = 0, i = l, j = mid + 1;
while (i <= mid && j <= r) {
if(q[i] <= q[j]) p[k ++ ] = q[i ++ ];
else p[k ++ ] = q[j ++ ];
}
while (i <= mid) p[k ++ ] = q[i ++ ];
while (j <= r) p[k ++ ] = q[j ++ ];
for (int i = 0; i < k; i ++ ) {
q[l + i] = p[i];
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i ++ ) scanf("%d", &q[i]);
merge_sort(q, 1, n);
for (int i = 1; i <= n; i ++ ) printf("%d ", q[i]);
return 0;
}