kizumi_header_banner_img

是先学算法,先刷题,还是先写日记呢?

加载中

文章导读

归并排序


avatar
RonF02 2026年1月31日 47

好吧,又是另一个分治。是一种稳定的算法,时间复杂度是O(nlogn)。
*稳定:若一个数组中两个数的值原来相同,经过某种排序算法排序后这两个数的顺序不发生变化,则称这种排序算法是稳定的

基本步骤

  1. 确定分界点mid
  2. 递归排序左半段,又半段
  3. 归并——合二为一(双指针算法),时间复杂度O(n)

代码

#include<bits/stdc++.h>
using namespace std;

void merge_sort(vector<int> &q, int l, int r, vector<int> &tmp)
{
    if (l >= r) return ;
    
    int mid = l + (r - l >> 1);
    merge_sort(q, l, mid, tmp), merge_sort(q, mid + 1, r, tmp);

    int k = 0, i = l, j = mid + 1;
    while (i <= mid && j <= r)
        if (q[i] <= q[j]) tmp[k ++] = q[i ++];
        else tmp[k ++] = q[j ++];   
    while (i <= mid) tmp[k ++] = q[i ++];
    while (j <= r) tmp[k ++] =q[j ++];

    for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
}

int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int n; cin >> n;
    vector<int> q(n);
    for (int i = 0; i < n; i ++ ) cin >> q[i];

    vector<int> tmp(n);
    merge_sort(q, 0, n - 1, tmp);

    for (int i = 0; i < n; i ++) cout << q[i] << ' ';
    cout << '\n';

    return 0;
}

应用:求逆序对数

ll merge_sort(int q[], int l, int r)
{
    if (l >= r) return 0;

    int mid = l + r >> 1;
    ll cnt = 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])
        {
            tmp[k++] = q[i++];
        }
        else 
        {
            tmp[k++] = q[j++];
            cnt += (mid - i + 1);
        }
    }


    while (i <= mid) tmp[k++] = q[i++];
    while (j <= r) tmp[k++] = q[j++];


    for (int i = l, j = 0; i <= r; i++, j++) 
        q[i] = tmp[j];

    return cnt;
}

代码如上,核心添加了计数模块。我们在执行每一段的核心代码时,其左右两半总是排序好的。因此,一旦出现左半段的数(下标为i)大于右半段的数(下标为j),则说明从第i个数到第mid个数都大于第j个数,故逆序对的数量为(mid – i + 1)。
后续只需要累加即可


2月3日补充

逆序对数一定要严格大于,今天复习的时候踩坑了。



评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字
插入代码
RonF02的博客

个人信息

avatar

24
文章
2
评论
1
用户