1.归并排序的基本思想
归并排序的基本思想就是把一个数组不断地分成数量尽可能相等的两部分,直至每个部分只包含一个元素。我们再将每两个部分的元素进行排序,然后合成一个部分,再将该部分与上一个他被分隔开的另一部分进行排序,再合成一个部分,不断循环可以使数组完成排序
2.代码实现
我们以从小到大到大给数组归并排序为例:
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
const int N = 1000010;
int q[N], temp[N];//q为原数组,temp是临时数组存储每个被临时排好的部分
void merge_sort(int q[], int left, int right) {
//此时表示数组已经被分割成单个元素一个部分了,这样我们就不再进行递归分割了
if (left >= right) return;
int middle = (left + right) >> 1;//把每个部分的中间元素当作边界,便于均分
//把数组进行递归分割成两个部分
merge_sort(q, left, middle), merge_sort(q, middle + 1, right);
int k = 0, i = left, j = middle + 1;
//while循环内的元素保证每个部分的元素不会越界到其它部分
while (i <= middle && j <= right) {
//经过不断的递归,此时i和j两个部分的数组已经有序了
//我们将两个部分的第一个元素进行比较,小的存入temp中
if (q[i] <= q[j]) temp[k++] = q[i++];
else temp[k++] = q[j++];
}
//一个部分的元素全部存完后另一部分还有元素没存入,我们将剩下的全部一起存入
//两个部分都是有序的,一个部分的较小元素均全部存进去了,那么剩下的肯定全部大于已存入元素且有序
while (i <= middle) temp[k++] = q[i++];
while (j <= right) temp[k++] = q[j++];
//把临时数组中存储的元素全部存入q中改变q原有的顺序使其变得部分有序
for (int m = left, n = 0; m <= right; m++, n++) q[m] = temp[n];
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> q[i];
merge_sort(q, 0, n - 1);
for (int i = 0; i < n; i++) cout << q[i] << " ";
return 0;
}
3.写代码踩过的一些坑
(1)漏写for (int m = left, n = 0; m <= right; m++, n++) q[m] = temp[n];
初学时不理解这条代码的作用,加上一个认知误区就是认为最后的输出结果就是temp数组内的元素,所以我认为q内的数据无论是否改变对结果影响都不大。现在纠正temp的作用是临时存储q某一部分排好序的元素,将这一部分的所有元素排序好后将temp的元素赋予q,此时q的一小部分已经局部有序了,然后有序的两个部分再合并排序好
(2)两个指针的限制
i和j都是有自己的范围的,所以在实现代码的过程中,我们要对i、j的范围进行限定,i只能在前半部分,j只能在后半部分