基础算法2:归并排序

归并排序

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

基本步骤

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

代码

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];
}

应用:求逆序对数

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)。
后续只需要累加即可

补充

逆序对数根据题意一定要严格大于,否则会踩坑

posted @ 2026-05-18 17:12  RonF02  阅读(5)  评论(0)    收藏  举报