計算氣泡排序的交換次數:
逆序數概念:在乙個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為乙個逆序
乙個排列中所有逆序個數總和叫做這個排列的逆序數。 所以氣泡排序結束即是所有的逆序數為0
思路:
暴力:我們要計算逆序數,即使要統計出該值位置之前有多少個數比他大.我們用 arr 陣列來表示序列值,則 posx
y , 有valuex>valuey .那麼可以得到 (o n2) 的方法
for(int px = 1; px<=n ; px++)view code}
我們在換個統計的思路,我們用乙個 vis 陣列來記錄,在前 i 個位置,有哪些值已經出現。這樣,比如當前位置為 3 值為4 ,在此之前已經有5和3被記錄,即原序列為 3 5 4 1 2,那麼我們
只需要遍歷統計值大於 4 的位置之前有多少出現。上例中從4遍歷到5則有vis[5]=1,所以逆序就有乙個.
而樹狀陣列是乙個用於維護字首和的工具,所以我們維護乙個vis從 當前值到最大值(最大位置)的乙個字首和(逆向字首和),即可快速得出答案
當然由於逆向不太好寫,我們可以反向來統計,比如上例中 3 5 4 1 2,第乙個位置3由於提早出現,之後的1和2會產生乙個貢獻,所以我們統計該位置為之後位置產生的逆序數貢獻就可以正向求字首和。
而之前則是統計當前位置之前出現的值對該位置的逆序貢獻。所以在後面**中貢獻值為 j - bit[i].
而維護字首和的樹狀陣列複雜度為 o( logn) ,所以將複雜度降為 o( nlogn)
#include #define ios ios::sync_with_stdio(0); cin.tie(0);#define mp make_pair
#define accept 0
using
namespace
std;
typedef
long
long
ll;typedef unsigned
long
long
ull;
typedef pair
pii;
const
double pi = acos(-1.0
);const
double esp = 1e-9
;const
int inf = 0x3f3f3f3f
;const
int maxn = 1e5+7
;const
int maxm = 1e6+7
;const
int mod = 1e9+7
;const
int maxl = 1e6+7
;int
n;int
bit[maxn];
intarr[maxn];
intvis[maxn];
//樹狀陣列維護的字首和
int sum(int
i)
returns;}
//單點更新
void add(int i,intx)}
void
solve()
//暴力的解法
//for(int i=0;i//
int cnt = 0;
//for(int j=0;j//
if(vis[j]) cnt++;//}
//ans += i - cnt;
//vis[arr[i]] =1; //}
printf("
%d\n
",ans);
}int
main()
solve();
return
0;
}
氣泡排序中交換次數與比較次數
氣泡排序的過程中每次交換就是消除乙個逆序對,而比較次數由其外層迴圈確定,因為內層是肯定迴圈至結束的。用了歸併排序求逆序對,樹狀陣列求乙個數的最大逆序對數。內部迴圈的次數為n 1,n 2.n m 數列求和。如下,大家可以測試下。include include include include inclu...
氣泡排序中資料交換的次數
problem description 聽說過氣泡排序麼?一種很暴力的排序方法。今天我們不希望你用它來排序,而是希望你能算出從小到大氣泡排序的過程中一共進行了多少次資料交換。input 輸入資料的第一行為乙個正整數 t 表示有 t 組測試資料。接下來t行,每行第乙個整數n,然後有n個整數,無序。0o...
運用BIT處理氣泡排序的交換次數問題
題意 給定乙個1 n的排列a0,a1,a2,a n 1 求對這個數列進行氣泡排序所需要的交換次數。在資料較大時,用常規的雙重for迴圈來求解交換次數就會因為複雜度太高而存在tle的情況,所以可以利用樹狀陣列善於查詢兩個數之間的數字和的優勢進行解題。首相樹狀陣列的基本操作就是bit的求和以及bit的值...