1. 程式人生 > 實用技巧 >資料結構之分治

資料結構之分治

分治

  • 利用分治演算法求一組資料的逆序對個數

背景

逆序數:也就是說,對於n個不同的元素,先規定各元素之間有一個標準次序(例如n個 不同的自然數,可規定從小到大為標準次序),於是在這n個元素的任一排列中,當某兩個元素的先後次序與標準次序不同時,就說有1個逆序。一個排列中所有逆序總數叫做這個排列的逆序數。

定義

在一個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為一個逆序。一個排列中逆序的總數就稱為這個排列的逆序數。逆序數為偶數的排列稱為偶排列;逆序數為奇數的排列稱為奇排列。如2431中,21,43,41,31是逆序,逆序數是4,為偶排列。

問題求解

分治法求逆序數相當於在歸併排序的過程中加上相應的逆序數的數目。

假設陣列A被劃分成前半部分(A[left]->A[mid]),後半部分(A[mid+1],A[right])

假設前半部分與後半部分各自都是從小到大排好序的,若A[left]<A[mid+1]那麼由A[mid+1]這個數與陣列前半部分造成的逆序數目是mid-left+1,這個數在接下來的逆序數中不用再考慮,反之類同。

使用分治法解決該問題的時間複雜度為O(N*log(N)).

 1 #include<iostream>
 2 #include<conio.h>
 3 using namespace std;
 4 int merge(int *A,int left,int mid,int right){
 5     int *temp=new int[right-left+1];
 6     int num=0;
 7     int i=left;
 8     int j=mid+1;
 9     int k;
10     int index=0;
11     for(;i<=mid&&j<=right;){
12         if(A[i]>A[j]){
13             num+=mid-i+1;
14             temp[index]=A[j];
15             j++;
16         }
17         else{
18             temp[index]=A[i];
19             i++;
20         }
22         index++;
23     }
24     //i=mid的時候,A[i]位置的數還未填充到陣列temp中
25     //因此判斷條件包含等於號
26     if(i<=mid)
27         for(;i<=mid;i++){
28             temp[index]=A[i];
29             index++;
30         }
32     if(j<=right)
33         for(;j<right;j++){
34             temp[index]=A[j];
35             index++;
36         }
3738     for(k=0;k<right-left+1;k++)
39         A[left+k]=temp[k];
40 
41     delete []temp;
42     return num;
43 }
45 int inversion(int *A,int left,int right){
46     if(left>=right)
47         return 0;
48     int mid=(left+right)/2;
49     int num1=inversion(A,left,mid);
50     int num2=inversion(A,mid+1,right);
51     return num1+num2+merge(A,left,mid,right); 
54 }
55 int main()
56 {
57     int A[5]={9,8,7,6,5};
58     cout<<inversion(A,0,4)<<endl;
59     _getch();
60 }

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e4;
int n;
int a[maxn], t[maxn];

void read()
{
cin >> n;
for(int i = 0; i < n; ++i)
cin >> a[i];
}

int countReversefewByMergeSort(int arr[], int left, int right, int tempArr[])
{
int cnt = 0;
if(left < right)
{
int mid = left + (right-left)/2;
cnt += countReversefewByMergeSort(arr, left, mid, tempArr);
cnt += countReversefewByMergeSort(arr, mid+1, right, tempArr);
int i = left, j = mid, k = left;
while(i < mid || j < right)
{
if(j >= right || (i < mid && arr[i] <= arr[j]))
tempArr[k++] = arr[i++];
else
{
tempArr[k++] = arr[j++];
cnt += mid-i;
}
}
for(k = left; k < right; ++k)
arr[k] = tempArr[k];
}
return cnt;
}

void solve()
{
cout << countReversefewByMergeSort(a, 0, n, t);
}

int main()
{
read();
solve();
return 0;
}