先来看这样一个问题,现在你有两个有序数组a和b,如何把他们合并为一个新的有序数组c?
方法很简单,用两个变量p1和p2分别表示两个数组未被取出的元素中最小元素的下标,初始为 0。然后每次取出a[p1]和b[p2]中较小的那个放进新的数组里。如果取出的是a[p1],那p1就自增 1;反之,p2就自增 1。
如果有数组被取空了,那就把另一个数组剩下的都放进来就可以了。
参考代码如下:
int n = 5, m = 5; // 两个数组的大小
int a[5] = {1, 3, 5, 7, 9};
int b[5] = {2, 4, 6, 8, 10};
int c[10];
int p1 = 0, p2 = 0, p = 0;
while (p1 < n && p2 < m) {
if (a[p1] <= b[p2]) {
c[p] = a[p1];
p1++;
} else {
c[p] = b[p2];
p2++;
}
p++;
}
while (p1 < n) {
c[p] = a[p1];
p++;
p1++;
}
while (p2 < m) {
c[p] = b[p2];
p++;
p2++;
}
归并排序的基本思想是分治,每次把待排序的区间分成两半,递归地处理。等到左右两部分都是有序后,再进行归并操作让整个数组有序。
参考代码如下:
int a[100005], b[100005];
void merge(int l, int r) {
int p1 = l, mid = (l + r) / 2, p2 = mid + 1, p = l;
while (p1 <= mid && p2 <= r) {
if (a[p1] <= a[p2]) {
b[p] = a[p1];
p1++;
} else {
b[p] = a[p2];
p2++;
}
p++;
}
while (p1 <= mid) {
b[p] = a[p1];
p++;
p1++;
}
while (p2 <= r) {
b[p] = a[p2];
p++;
p2++;
}
for (int i = l; i <= r; i++) {
a[i] = b[i];
}
}
void merge_sort(int l, int r) {
if (l == r) {
return;
}
int mid = (l + r) / 2;
merge_sort(l, mid);
merge_sort(mid + 1, r);
merge(l, r);
}
上面的merge_sort
函数每次对 [l,r] 区间的元素进行归并排序。如果当前区间只有一个元素,就说明已经排序好了,直接返回。否则,把区间划分为 [l,mid] 和 [mid+1,r] 两部分递归处理,其mid=⌊2l+r⌋。
执行归并操作时,先把两个有序的区间合并到一个新数组b
中,最后再复制回原数组里
完整代码
#include <iostream>
using namespace std;
int a[100005], b[100005];
void merge(int l, int r) {
int p1 = l, mid = (l + r) / 2, p2 = mid + 1, p = l;
while (p1 <= mid && p2 <= r) {
if (a[p1] <= a[p2]) {
b[p] = a[p1];
p1++;
} else {
b[p] = a[p2];
p2++;
}
p++;
}
while (p1 <= mid) {
b[p] = a[p1];
p++;
p1++;
}
while (p2 <= r) {
b[p] = a[p2];
p++;
p2++;
}
for(int i = l; i <= r; i++){
a[i] = b[i];
}
}
void merge_sort(int l, int r) {
if (l == r){
return ;
}
int mid=(l+r) / 2;
merge_sort(l,mid);
merge_sort(mid + 1,r);
merge(l,r);
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
merge_sort(0, n - 1);
for (int i = 0; i < n; i++) {
cout << a[i] << " ";
}
return 0;
}