计算数组的逆序对个数
? ? ? 問題:給定一個數組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子數組L[0...n1]=A[0...n/2]和R[0...n2]=A[n/2+1...n-1],總的逆序對=L中的逆序對+R中的逆序對+橫掃L和R的逆序對;
? ? ? 比如將數組 2 3 8 6 1分為兩部分 L: 2 3 8和 R:6 1,于是左邊L中逆序對0個,右邊R中逆序對(6,1)共1對,那么橫掃L與R的有(2,1),(3,1),(8,6),(8,1)一共4對,于是總的對數為0+1+4=5對。現在問題的難點就是如何求中間橫掃那部分的逆序對,如果暴力來求,必然O(n2)。我們先來看看這樣的一個事實,如果將L排好序,將R也排好序,這時候中間橫掃那部分的逆序對個數不會改變,這是因為L與R是分開的。這樣以來,我們可以用歸并排序的思路設計這個算法,基于這樣設計之所以正確在于每一次子序列的排序的歸并都是在該該序列逆序對計算完成后進行的。C++代碼如下:
#include<iostream> using namespace std; #define MAX_VALUE 12343564 int Count_Reversations(int *A, int n); int Merge_Reversations(int *A, int p, int r); int main(){int a[5] = { 2,3,8,6,1 };cout << Count_Reversations(a, 5) << endl;return 0; } int Count_Reversations(int*A, int n){ //接口函數return Merge_Reversations(A, 0, n - 1); } int Merge_Reversations(int *A, int p, int r){if (p>=r)return 0;int i, j, k,mid,n1,n2, reversations = 0;mid = (p + r) >> 1;int next_count= Merge_Reversations(A, p, mid) + Merge_Reversations(A, mid + 1, r);n1 = mid - p + 1;n2 = r - mid;int *R = new int[n2 + 1];int *L = new int[n1 + 1];for (i = 0; i < n1; i++)L[i] = A[i + p];for (j = 0; j < n2; j++)R[j] = A[j + mid + 1];L[n1] = R[n2] = MAX_VALUE; //設置為最大值,當做哨兵i = j = 0;for (k = p; k <= r; k++){if (L[i]>R[j]){reversations +=n1-i;A[k] = R[j++];}elseA[k] = L[i++]; }delete[]R, L;return reversations +next_count; }?
轉載于:https://www.cnblogs.com/td15980891505/p/5143866.html
總結
以上是生活随笔為你收集整理的计算数组的逆序对个数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: windows和Linux内存的对齐方式
- 下一篇: mysql登录报错 ERROR 1045