求逆序对数

设A[1..n]是一个包含N个非负整数的数组。如果在i〈 j的情况下,有A〉A[j],则(i,j)就称为A中的一个逆序对。
例如,数组(3,1,4,5,2)的“逆序对”有<3,1>,<3,2><4,2><5,2>,共4个。
使用归并排序可以用O(nlogn)的时间解决统计逆序对个数的问题
定义:对于一个给定的数列,如果有i<j,且Ai>Aj,则称(i,j)为一逆序对.
要解决的问题是,给出一个数列,求出这个数列包含多少个逆序对

今天在《算法导论》上看到了这题,提示用归并算法,没想明白。在google搜了一下,有一些实现但是没讲清楚,后来自己动手做了一下算是弄明白了。

普通实现 O(n^2):

 

template<class Iterator>
int countInversePair(Iterator first, Iterator last)
{
    int count = 0;
    Iterator it;
    while(first != last)
    {
        it = first;
        while(it != last)
        {
            if(*it < *first)
                count++;
            it++;
        }
        first++;
    }

    cout << count << endl;

    return count;
}


归并实现 O(nlogn):

int gCount = 0;

template<class Iterator>
int merge(Iterator begin, Iterator mid, Iterator end)
{
    Iterator iL = begin;
    Iterator iR = mid;

    int count = distance(begin, end);
    vector<int> v(count);
    vector<int>::iterator it = v.begin();

    while(iL != mid && iR != end)
    {
        if(*iL <= * iR)
        {
            *it++ = *iL++;
        }
        else
        {
            gCount += distance(iL, mid);
            *it++ = *iR++;
        }
    }

    if(iL == mid) copy(iR, end, it);
    if(iR == end) copy(iL, mid, it);

    copy(v.begin(), v.end(), begin);

    return 0;
}

template<class Iterator>
int mergeSort(Iterator begin, Iterator end)
{
    int count, step;
    count = distance(begin, end);

    if(count <= 1)
    {
        return 0;
    }

    step = count / 2;

    mergeSort(begin, begin + step);
    mergeSort(begin + step, end);

    merge(begin, begin + step, end);

    return 0;
}


 

重点在 gCount += distance(iL, mid)

逆序对数实质就是插入排序过程中要移动元素的次数

归并的时候 前后两个序列都是有序的,可以把这个过程想象成插入排序,将第二个序列的内容插入到第一个有序的序列中

那么插入第二个序列中的元素时,要移动的元素的位数即第一个序列中还未插入到新序列中的元素的个数

即: distance(iL, mid)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值