逆序数的几种球求法(归并排序+树状数组)

  1. 暴力
    对每个数遍历它之前的所有数有比它大的逆序数就加一
  2. 利用归并排序
    每改变一次排序逆序数就加一
int temp[100];  //存储已排序的数组
int ans; //代表逆序数的个数
int a[100] = { 1,8,6,3,4,2}; //存储原数组信息

void merge(int i, int mid, int j) 
{
    int left = i;
    int right = j;
    int m = mid + 1;
    int t = i; //递增temp数组的插入元素位置

    while (left <= mid && m <= j) 
    { //两部分数组都没到尽头
        if (a[left] > a[m]) 
        {
            temp[t++] = a[m++];
            ans += mid - left + 1;  //前面区间全部比a[m]大
        }
        else
            temp[t++] = a[left++];
    }
    while (left <= mid) 
    { //后面数组已没有元素
        temp[t++] = a[left++];
    }
    while (m <= j) 
    {
        temp[t++] = a[m++];
    }
    for (int k = i; k <= j; k++) 
    {  //把数组替换到a数组中
        a[k] = temp[k];
    }
}

void mergesort(int i, int j) 
{
    if (i < j) 
    {
        int mid = (j + i) / 2;
        mergesort(i, mid);
        mergesort(mid + 1, j);
        merge(i, mid, j);
    }
}

3.树状数组
先在数组中放最大的元素
然后判断前面已经放置了几个元素了
然后放第二大,再判断前面有几个
依次类推

int aa[maxn];
int c[maxn]; //树状数组
int n;

struct Node
{
    int v;
    int order;
}a[maxn];

bool cmp(Node a, Node b)
{
    return a.v < b.v;
}

int lowbit(int k)
{
    return k&(-k); 
}

void update(int t, int value)
{     //即一开始都为0,一个个往上加(+1),
    int i;
    for (i = t; i <= n; i += lowbit(i))
        c[i] += value;  
}

int getsum(int t)
{  //即就是求和函数,求前面和多少就是小于它的个数
    int i, sum = 0;
    for (i = t; i >= 1; i -= lowbit(i))
        sum += c[i];
    return sum;
}

int main()
{
    int i;
    while (scanf("%d", &n), n)
    {
        for (i = 1; i <= n; i++) 
        {
            scanf("%d", &a[i].v);
            a[i].order = i;
        }
        sort(a + 1, a + n + 1,cmp);
        memset(c, 0, sizeof(c));
        for (i = 1; i <= n; i++)
            aa[a[i].order] = i;
        int ans = 0;
        for (i = 1; i <= n; i++)
        {
            update(aa[i], 1);
            ans += i - getsum(aa[i]); 
        }
        printf("%d\n", ans);
    }
    return 0;

猜你喜欢

转载自blog.csdn.net/wuswi0412/article/details/81410113