思路:

1.首先分割成一个个独立的部分
2.然后组合,借助临时数组
3.把其中那个没有遍历完全的数组元素填到临时数组中
4.物归原主

  1. #include <iostream>
  2. using namespace std;
  3. const int N = 1e5 + 10;
  4. int n;
  5. int a[N], temp[N]; // temp作为临时数组
  6. void merge_sort(int a[], int l, int r) {
  7. if (l >= r) return; // 这里不管在应用的时候还是单纯归并排序,这里可以都可以写成==替代
  8. int mid = l + r >> 1;
  9. merge_sort(a, l, mid);
  10. merge_sort(a, mid + 1, r);
  11. int k = 0, i = l, j = mid + 1; // 实际两个有序序列的合并过程
  12. while (i <= mid && j <= r) {
  13. if(a[i] < a[j]) temp[k++] = a[i++];
  14. else temp[k++] = a[j++];
  15. }
  16. while (i <= mid) temp[k++] = a[i++];
  17. while (j <= r) temp[k++] =a[j++];
  18. for (int i = l, j = 0; i <= r; i++, j++) a[i] = temp[j]; // 物归原主过程
  19. }
  20. int main() {
  21. scanf("%d", &n);
  22. for (int i = 0; i < n; i++) scanf("%d" , &a[i]);
  23. merge_sort(a, 0, n - 1);
  24. for (int i = 0; i < n; i++) printf("%d ", a[i]);
  25. }

image.png

逆序对(归并的应用)

牛客网对应编程题的链接,思路搞得y总的视频,明白原理最重要

1 2 3 5 4 逆序个数是1
基本思想,整个区间分成俩区间以后,总的逆序的个数 = 左边区间逆序个数和右边区间逆序个数的和 + 两个区间之间的一个逆序。和走楼梯思路一直,基本思想就是基于分治的思想。两个区间的如何计算?

answer:在合并两个区间的时候计算, 第二个区间的第一个元素当 a[i] > a[j],此时从i到mid整个区间部分都是大于j指针所指的元素,因此res 需要在加上前面的 merge_sort(l, mid) 和 merge_sort(mid + 1, r)的基础上,加上第一区间比第二区间每个元素大的总个数。就是上面一段红色部分个数。

  1. #include <iostream>
  2. using namespace std;
  3. const int N = 1e5 + 10;
  4. int n;
  5. int a[N], temp[N];
  6. typedef long long LL;
  7. LL merge_sort(int l, int r) {
  8. if (l >= r) return 0;
  9. int mid = l + r >> 1;
  10. LL res = merge_sort(l, mid) + merge_sort(mid + 1, r); // 第一个区间内部和第二个区间内部的逆序个数。
  11. int k = 0, i = l, j = mid + 1;
  12. while (i <= mid && j<= r) {
  13. if (a[i] <= a[j]) temp[k++] = a[i++];
  14. else {
  15. temp[k++] = a[j++];
  16. res += mid - i + 1; // 两个区间之间的逆序个数。
  17. }
  18. }
  19. while (i <= mid) temp[k++] = a[i++];
  20. while (j <= r) temp[k++] = a[j++];
  21. for (int i = l, j = 0; i <= r; i++, j++) a[i] = temp[j];
  22. return res;
  23. }
  24. int main() {
  25. scanf("%d", &n);
  26. for (int i = 0; i < n; i++ ){
  27. scanf("%d", &a[i]);
  28. }
  29. cout << merge_sort(0, n - 1) << endl;
  30. return 0;
  31. }