前幾天看樹狀陣列,昨天做求逆序數的題,發現歸併排序求逆序數更快一點,或者說是排序的時候順便把逆序數給求了,於是學了一下,順便整理一下。。。。。。
歸併排序:說白了就是把一列數 遞迴 的分解為多個有序的子串行,然後再把子序列合併 為一列有序的數。
這就涉及兩個過程:
1,遞迴劃分:把序列分成個數盡量相等的兩部分,兩邊的元素分別排好序;
2,合併求解:把兩個有序表合成乙個;
下面來說明上面兩個過程:
第一步:假如給定乙個序列:,第一次劃分後分為兩個子串行,,當然現在兩邊的序列依舊無序,現在我們要做的使序列有序(當然我們不能直接用排序函式直接對兩部分排序,要不還要歸併排序幹嘛),那就繼續第一步,把兩個子串行繼續遞迴分解,當遞迴到每個子串行中只包含乙個元素時,呵呵,這個子串行當然就是有序的了,當第一步結束後我們得到如下七個子串行,,,,,,,並且每個子串行有序。
第二步:分別對兩個有序子串行合併,對上面七個子串行第一次合併後是,,,,第二次合併後是,;第三次合併後就是,排序完成。
現在我們來說如何把兩個有序子串行合併為乙個有序序列:對序列1和序列2;我們先比較序列1的第乙個元素和序列2的第乙個元素,小的元素存入序列3中,計數器向後加1,重複上面步驟,直到其中乙個子串行為空,此時把另外乙個未空序列中剩餘元素複製到3中即可完成合併。詳見**:
//將有序陣列a和b合併到c中
void merge(int a, int n, int b, int m, int c)
while (i < n)
c[k++] = a[i++];
while (j < m)
c[k++] = b[j++];
}
當然上面的只是對於兩個陣列a,b的操作,我們所要合併的兩個子串行在乙個序列中,以mid分開,所以**如下:
//將a的兩部分有序數列a[first...mid]和a[mid+1...last]合併
void merge(int a, int first, int mid, int last, int c)
while (i <= m)
c[k++] = a[i++];
while (j <= n)
c[k++] = a[j++];
for (i = 0; i < k; i++)
a[first + i] = c[i];//因為合併的序列是從first開始的,所以把合併後的序列c賦給原序列應該從first位置開始
}
由上面**可見,合併操作只需遍歷一遍兩個子串行,故時間複雜度為o(n);
當然上面**簡單易懂但略顯繁瑣,稍微精簡的如下:
int merge(int a,int first,int mid,int last,int c)
//求逆序數時只需改為左邊,下面解釋
}for(i=0;i上面的看完應該會序列合併了,那現在就用遞迴實現序列劃分與合併,**如下:
void merge_sort(int a,int first,int last,int c)
{ if(first由於遞迴分解子串行,相當於二分子序列,故時間複雜度為o(logn);
故總時間複雜度為nlogn;
至此,歸併排序已經說完,下面是更加簡潔的**,一氣呵成:
//歸併排序
void merge_sort(int a,int first,int last,int c)
{ if(last-first>1)//
{int mid=first+(last-first)/2;
int p=first,q=mid,i=first;//從中間劃分為盡量相等兩部分
merge_sort(a,first,mid,c);//遞迴呼叫使左邊有序
merge_sort(a,mid,last,c);//遞迴呼叫使右邊有序
while(p=last||(p
為什麼歸併排序就順便把逆序數給求了呢?其實很簡單,因為我們要合併的兩個子串行是排好序的,當右邊子串行中的數a[i]複製給c陣列時,左邊子串行中沒來的及複製到c中的那些數就是所有比a[i]大的數,故此時在累加器中加上左邊剩餘元素個數即可,在**中有標記。
終於整理完了,我想說一句,歸併排序除了方便理解遞迴和求逆序數(樹狀陣列也行),不知道幹嘛,排序速度不如c++ stl中的sort,穩定排序也不如stable_sort方便,呵呵~~~
求逆序數 逆序數 歸併排序
求排列的逆序數 分治 一 題目描述 總時間限制 1000ms 記憶體限制 65536kb 描述 在internet上的搜尋引擎經常需要對資訊進行比較,比如可以通過某個人對一些事物的排名來估計他 或她 對各種不同資訊的興趣,從而實現個性化的服務。對於不同的排名結果可以用逆序來評價它們之間的差異。考慮1...
歸併排序 求逆序數
首先需要了解逆序對的概念 如果在乙個序列 數列中,滿足 則ax和ay稱為一對逆序對。現在考慮乙個問題 對乙個大小為n 即有n個元素 元素隨機無序且唯一的整數序列中,平均有多少個逆序對?乙個構造證明的方法如下 設乙個隨機無序且元素唯一的整數序列為 我們令lr為l的反向序列,即 然後在lr中任取兩個數,...
歸併排序求逆序數
輸入 n 陣列中元素個數 x 最後所存在的每對逆序對所需要花費的錢 y 按任意順序交換陣列中相鄰兩個元素所要花費的錢 n個陣列中元素 輸出 求使陣列變為公升序所需要的最少 即求該陣列的逆序數 按陣列順序 任意順序交換次數均為該陣列的逆序數次 歸併排序求逆序數 歸併排序採用分治策略 ex 重點在於合併...