逆序对个数 - 冒泡排序

设一个序列为: a[0], a[1], ..., a[n-1],一个逆序对是指:{ (a[i], a[j]) | a[i] > a[j], i < j }。

统计一个序列中的逆序对个数,可以使用冒泡排序法、二路归并法等。这里介绍利用冒泡排序统计逆序对个数的方法。

核心思想:冒泡排序中,每进行一次交换,则序列的逆序对个数-1。

证明:设冒泡排序过程中 a[i] 与 a[i+1] 进行了一次交换,这说明 a[i] > a[i+1]。序列中逆序对可分为四种:① 非 a[i] 和非 a[i+1] 构成的逆序对;②  a[i] 和非 a[i+1] 构成的逆序对;③  a[i+1] 和非 a[i] 构成的逆序对;④  a[i] 和 a[i+1] 构成的逆序对。易知,a[i] 与 a[i+1]  交换时,①、②、③ 类型构成的逆序对个数没变,而类型④的逆序对个数由1变为0,故每进行一次交换序列逆序对个数减少1。

冒泡排序统计逆序对的C++程序:

#include <cstdio>
#include <string>
#include <functional>
using namespace std;

/* 对T类型的数组a[lo, hi)进行排序,并返回逆序对个数。
   比较由函数对象compare实现,compare(a, b):当 a <= b,返回true。*/
template <class T, class Comp>
int countInversionBubble(T * a, int lo, int hi, Comp compare)
{
    int n_inv = 0;    // 逆序对个数
    while ( lo < hi - 1 )
    {
        int last = lo - 1;    // last标示一轮气泡中最后一次交换发生在a[i]与a[i+1]间。
        for ( int i = lo; i < hi - 1; ++i )
        {
            if ( !compare(a[i], a[i+1]) )
            {
                T t = a[i+1]; a[i+1] = a[i]; a[i] = t;    // 交换a[i]与a[i+1]
                ++n_inv;
                last = i;
            }
        }
        hi = last + 1;
    }
    return n_inv;
}
// 测试
int main()
{
    int a1[] = {1};
    int n1 = countInversionBubble(a1, 0, 1, less<int>());    // 0

    int a2[] = {1, 2, 3};
    int n2 = countInversionBubble(a2, 0, 3, less<int>());    // 0

    int a3[] = {5, 4, 3, 2, 1};
    int n3 = countInversionBubble(a3, 0, 5, less<int>());    // 10

    int a4[] = {5, 1, 3, 2, 4};
    int n4 = countInversionBubble(a4, 0, 5, less<int>());    // 5

    printf("%d %d %d %d\n", n1, n2, n3, n4);
    return 0;
}

原文地址:https://www.cnblogs.com/fyqq0403/p/10503237.html

时间: 2024-11-17 10:07:58

逆序对个数 - 冒泡排序的相关文章

计算数组的逆序对个数

问题:给定一个数组A,A存有n个互不相同的整数.定义:若i<j且A[i]>A[j],则称(i,j)为A的一个逆序对(inversation).设计一个O(nlogn)算法求A中逆序对个数. 显然最坏情况下逆序对有n(n-1)/2个,如;5 4 3 2 1完全逆序,逆序对有(5-1)*5/2=10对.若用暴力来求解,则时间复杂度为O(n2),显然比这不是一个好的算法.下面考虑用归并排序的类似方法来解决这个问题. 首先,对于一个长度为n的数组A[0...n-1],我们可以将它分为两个长度为n/2子

P1136 归并排序,求逆序对个数

这道题从看到它开始到做出来,已经过了快两周[因为第一次思路完全跑偏写的是暴力模拟想水过]: 题意是这样的:  jzabc除了对多米诺骨牌感兴趣外,对赛车也很感兴趣.上个周末他观看了一场赛车比赛.他总是能想出许多稀奇的问题.某一时刻,他看到有n辆车(总是匀速行驶)在同一直线上,并且处在一个无限长度的直道上,而且n辆车有严格的先后之分.他通过特殊的器材测出了每一辆车的速度.那么问题出现了,如果有两辆车A车和B车,A车在B车的后面,并且A车的速度比B车的快,那么经过一段时间后,A车一定会超过B车.我们

POJ-2299 Ultra-QuickSort(逆序对个数)

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 57461   Accepted: 21231 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin

求逆序对(inversion)的个数

2-4 逆序对 设A[1...n]是一个包含n个不同数的数组,如果在i<j的情况下,有A[i]>A[j],则(i,j)就称为A中的一个逆序对(inversion). a)列出数组<2, 3, 8, 6, 1>的5个逆序对 b)如果数组的元素取自集合{1,2,...,n}, 那么, 怎样的数组含有最多的逆序对?它包含多少个逆序对? c)插入排序的运行时间与输入数组中逆序对的数量之间有怎样的关系?说明你的理由. d)给出一个算法,它能用Θ(nlgn)的最坏情况运行时间,确定n个元素的任

校内集训 miku set模拟冒泡排序 逆序对

题意 给你一个长为\(n\)的序列,进行\(m\)次操作,每次对一个区间进行排序,求最后的序列\((n <= 1500, m <= 1e6)\) 这道题目思维难度挺大的 对于一个序列,排序的本质就是消除里面的所有逆序对 考虑冒泡排序的过程,每次也是交换\(a[i]>a[i+1]\)这个逆序对 这样子交换最多有\(n^2\)次 那么我们可以用一个数据结构模拟冒泡排序交换逆序对这个过程 用一个\(set\)维护所有逆序对的位置 每次暴力删除区间内所有逆序对 再把新产生的逆序对加入\(set\

树状数组求逆序对

给定n个数,要求这些数构成的逆序对的个数.除了用归并排序来求逆序对个数,还可以使用树状数组来求解.树状数组求解的思路:开一个能大小为这些数的最大值的树状数组,并全部置0.从头到尾读入这些数,每读入一个数就更新树状数组,查看它前面比它小的已出现过的有多少个数sum,然后用当前位置减去该sum,就可以得到当前数导致的逆序对数了.把所有的加起来就是总的逆序对数.题目中的数都是独一无二的,这些数最大值不超过999999999,但n最大只是500000.如果采用上面的思想,必然会导致空间的巨大浪费,而且由

BZOJ1786: [Ahoi2008]Pair 配对/1831: [AHOI2008]逆序对

这两道题是一样的. 可以发现,-1变成的数是单调不降. 记录下原有的逆序对个数. 预处理出每个点取每个值所产生的逆序对个数,然后dp转移. #include<cstring> #include<iostream> #include<cstdio> #include<map> #include<cmath> #include<algorithm> #define rep(i,l,r) for (int i=l;i<=r;i++)

2431: [HAOI2009]逆序对数列

2431: [HAOI2009]逆序对数列 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 954  Solved: 548[Submit][Status] Description 对于一个数列{ai},如果有i<j且ai>aj,那么我们称ai与aj为一对逆序对数.若对于任意一个由1~n自然数组成的数列,可以很容易求出有多少个逆序对数.那么逆序对数为k的这样自然数数列到底有多少个? Input 第一行为两个整数n,k. Output 写入一个整数,

POJ 2299 Ultra-QuickSort(归并排序&#183;逆序对)

题意  给你一个数组求其中逆序对(i<j&&a[i]>a[j])的个数 我们来看一个归并排序的过程: 给定的数组为[2, 4, 5, 3, 1],二分后的数组分别为[2, 4, 5], [1, 3],假设我们已经完成了子过程,现在进行到该数组的"并"操作: a: [2, 4, 5] b: [1, 3] result:[1] 选取b数组的1 a: [2, 4, 5] b: [3] result:[1, 2] 选取a数组的2 a: [4, 5] b: [3] r