逆序对个数 - 冒泡排序

Posted 风语轻轻

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了逆序对个数 - 冒泡排序相关的知识,希望对你有一定的参考价值。

       设一个序列为: 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; }

      

以上是关于逆序对个数 - 冒泡排序的主要内容,如果未能解决你的问题,请参考以下文章

loj2765 - 冒泡排序 题解

4.排序(上)

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

冒泡排序的交换次数 (树状数组)

冒泡排序

C语言将一组数从大到小排序 只能移动相邻的数 并且要求步骤最小 怎么设计逻辑