归并排序与逆序对的问题

逆序对

在一个序列中,有i<j,且a[i]>a[j],我们称这对数为逆序对。
一个序列的逆序对的数量即为序列的逆序数。

归并排序

归并排序用到了分治的思想。将大问题化成小问题在进行合并。
例:
在这里插入图片描述

如上图,我们在回溯的时候可以合并两个子区间来达到排序的效果。
如:[0,1]和[2,2]这两个区间合并,我们这里使用了一个临时数组在存合并之后的序列。合并完在用临时数组给原序列赋值。

void Merge_sort(vector<int> &data, int l, int r, int &ans)
{
    if(l >= r)
        return ;
    int m = (l + r) / 2;
    Merge_sort(data, l, m, ans);//递归左边
    Merge_sort(data, m + 1, r, ans);//递归右边
    int left = l, right = m + 1;
    vector <int> vv;//临时数组
    while(left <= m || right <= r)
    {
        if(left > m)//左边区间没有数了
        {
            vv.push_back(data[right ++]);
            continue;
        }
        if(right > r)//右边区间没有数了
        {
            vv.push_back(data[left ++]);
            continue;
        }
        if(data[left] <= data[right])//小的先放入临时数组
        {
            vv.push_back(data[left ++]);
        }
        else 
        {
            ans = (m - left + 1 + ans) % 1000000007;//求逆序数
            vv.push_back(data[right ++]);
        }
    }
    for(int i = l, j = 0; i <= r; i ++, j ++)//将临时数组赋值给原数组
        data[i] = vv[j];
}

归并排序与逆序数分析

上面代码中有:ans = (m - left + 1 + ans) % 1000000007
不考虑取模也就是:ans += m - left + 1
这是在当data[left] > data[right]时进行的。
也就是 左边的一个数大于右边的一个数。很明显满足逆序对的定义。
由于回溯之后每个子区间是有序的。所以left后面的数也大于data[left]。
那么有多少个这样的数呢。是(m - left + 1)个。
所以提供了(m - left + 1)个逆序对。

原创文章 83 获赞 6 访问量 2744

猜你喜欢

转载自blog.csdn.net/qq_43101466/article/details/106117234