算法學習(二)——樹狀數組求逆序數


1、什么是逆序數?
2、用樹狀數組求逆序數的總數
         2.1該背景下樹狀數組的含義
         2.2如何使用樹狀數組求逆序數總數
         2.3 C++實現代碼
目錄

 

1、什么是逆序數?

         在一個排列中,如果一對數的前后位置與大小順序相反,即前面的數大於后面的數,那么它們就稱為一個逆序。一個排列中逆序數的總數就是這個排列的逆序數。

 

2、用樹狀數組求逆序數的總數

         2.1該背景下樹狀數組的含義

         我們假設一個數組A[n],當A[n]=0時表示數字n在序列中沒有出現過,A[n]=1表示數字n在序列中出現過。A對應的樹狀數組為c[n],則c[n]對應維護的是數組A[n]的內容,即樹狀數組c可用於求A中某個區間的值的和。

         樹狀數組的插入函數(假設為 void insert(int i,int x) )的含義:在求逆序數這個問題中,我們的插入函數通常使用為insert( i , 1 ),即將數組A[i]的值加1 (A數組開始應該初始化為0,所以也可以理解為設置A[ i ]的值為1,即將數字i 加入到序列的意思 )。,同時維護c數組的值。

         樹狀數組中區間求和函數(假設函數定義為: int getsun(int i ) )的含義:該函數的作用是用於求序列中小於等於數字 i 的元素的個數。這個是顯而易見的,因為樹狀數組c 維護的是數組A的值,則該求和函數即是用於求下標小於等於 i 的數組A的和,而數組A中元素的值要么是0要么是1,所以最后求出來的就是小於等於i的元素的個數。

         所以要求序列中比元素a大的數的個數,可以用i - getsum(a)即可( i 表示此時序列中元素的個數)。

 

         2.2如何使用樹狀數組求逆序數總數

         首先來看如何減小問題的規模:

         要想求一個序列 a b c d,的逆序數的個數,可以理解為先求出a b c的逆序數的個數k1,再在這個序列后面增加一個數d,求d之前的那個序列中值小於d的元素的個數k2,則k1+k2即為序列a b c d的逆序數的個數。

         舉個例子加以說明:

  假設給定的序列為 4 3 2 1,我們從左往右依次將給定的序列輸入,每次輸入一個數temp時,就將當前序列中大於temp的元素的個數計算出來,並累加到ans中,最后ans就是這個序列的逆序數個數。

 

序列的變化(下划線為新增加元素)

序列中大於新增加的數字的個數

操作

{ }

0

初始化時序列中一個數都沒有

{4 }

0

往序列中增加4,統計此時序列中大於4的元素個數

{4 3 }

1

往序列中增加3,統計此時序列中大於3的元素個數

{4 3 2}

2

往序列中增加2,統計此時序列中大於2的元素個數

{4 3 2 1}

3

往序列中增加1,統計此時序列中大於1的元素個數

         當所有的元素都插入到序列后,即可得到序列{4 3 2 1}的逆序數的個數為1+2+3=6.

        

         2.3 C++實現代碼如下:

 

#include <iostream>
#include <string>
using namespace std;
#define N 1010
int c[N]; 
int n;
int lowbit(int i)
{
    return i&(-i);
}
int insert(int i,int x)
{
    while(i<=n){
        c[i]+=x;
        i+=lowbit(i);
    }
    return 0;
}

int getsum(int i)
{
    int sum=0;
    while(i>0){
        sum+=c[i];
        i-=lowbit(i);
    } 
    return sum;
}
void output()
{
    for(int i=1;i<=n;i++) cout<<c[i]<<" ";
    cout<<endl;
}
int main()
{
    while(cin>>n){
        int ans=0;
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;i++){
            int a;
            cin>>a;
            insert(a,1);
            ans+=i-insert(a);//統計當前序列中大於a的元素的個數
        }
        cout<<ans<<endl;
    }
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM