歸併排序&求逆序對數

來源:互聯網
上載者:User

歸併排序:

基本原理:與插入排序使用的“增量”方法不同,歸併排序使用另外一種策略:分治法

 

分治策略基本思想:將原問題劃分成n個規模較小而結構與原問題相似的小問題;遞迴地解決這些子問題,然後再合并其結果,就得到原問題的解。

 

分治模式在每一層遞迴上都有三個步驟;

分解(Divide):將原問題分解成這一系列子問題。

解決(Conquer):遞迴地解各子問題。若子問題足夠小,則直接求解。

合并(Combine):將子問題的結果合并成原問題的解。

 

合并排序演算法完全依照了上述模式,直觀地操作如下:

分解:將n個元素分成各含n/2個元素的子序列;

解決:用合并排序法對兩個子序列遞迴地排序;

合并:合并兩個已排序的子序列以得到排序結果;

 

時間複雜度:O(nlgn)

 

代碼實現:

#include<stdio.h>#define N 10 int A[N] ;void Merge(/*A*/int p,int q,int r) ;void MergeSort(/*A*/int p,int r) ;int main(void){int i,n ;freopen("in.txt","r",stdin) ;while(scanf("%d",&n) != EOF){for(i = 0 ; i < n ; i++){scanf("%d",&A[i]) ;}printf("You have input the List:\n") ;for(i = 0 ; i < n ; i++){printf("%-3d",A[i]) ;}printf("\n") ;MergeSort(/*A*/0,n-1) ; //not n but n-1printf("After Sort:\n") ;for(i = 0 ; i < n ; ++i){printf("%-3d",A[i]) ;}printf("\n\n") ;}return 0 ;}void MergeSort(/*A*/int p,int r) {int q = 0 ;if(p < r){q = p + (r-p)/2 ; //noticeMergeSort(/*A*/p,q) ;MergeSort(/*A*/q+1,r) ;Merge(/*A*/p,q,r) ;}}void Merge(/*A*/p,q,r) {int L[N], R[N] ;int i,j,k ;int nLeft,nRight ;nLeft = q + 1 - p ; //noticenRight = r - q ; //noticefor(i = 0 ; i < nLeft ; ++i ){L[i] = A[p+i] ;}for(j = 0 ; j < nRight ; ++j){R[j] = A[q+j+1] ;  //notice}i = 0 ;j = 0 ;for(k = p ; k < r && i<nLeft && j<nRight ; k++ ){if(L[i] <= R[j]){A[k] = L[i] ; i++ ;}else{A[k] = R[j] ; j++ ;}}if(i >= nLeft){for(; k <= r ; ++k,++j) {A[k] = R[j] ;}}else{for(; k <= r ; ++k,++i){A[k] = L[i] ;}}}

 

 

以上結論摘自《演算法導論》

 

----------------------------------------------------------------------------

演算法導論思考題:2-4逆序對

d)給出一個演算法,它能用O(nlgn)的最壞情況已耗用時間,確定n個元素的任何排列中逆序對的數目。(提示:修改合并排序)

答:其實就是合并兩個子序列時,出現右邊元素小於左邊元素的情況,亦即R[j]<L[i]時,出現逆序對。此時L[i+1...n1]裡的元素均比R[j]大,而R[j]又在它們的後面。所以,此時的逆序對數:n1-i。後面的元素以此類推。

 

代碼實現:

#include<stdio.h>#define N 10 int A[N] ;int nTotalInversion = 0 ;void Merge(/*A*/int p,int q,int r) ;void MergeSort(/*A*/int p,int r) ;int main(void){int i,n ;freopen("in.txt","r",stdin) ;while(scanf("%d",&n) != EOF){nTotalInversion = 0 ;for(i = 0 ; i < n ; i++){scanf("%d",&A[i]) ;}printf("You have input the List:\n") ;for(i = 0 ; i < n ; i++){printf("%-3d",A[i]) ;}printf("\n") ;MergeSort(/*A*/0,n-1) ; //not n but n-1printf("The Inversions are %d.\n\n",nTotalInversion) ;}return 0 ;}void MergeSort(/*A*/int p,int r) {int q = 0 ;if(p < r){q = p + (r-p)/2 ; //noticeMergeSort(/*A*/p,q) ;MergeSort(/*A*/q+1,r) ;Merge(/*A*/p,q,r) ;}}void Merge(/*A*/p,q,r) {int L[N], R[N] ;int i,j,k ;int nLeft,nRight ;nLeft = q + 1 - p ; //noticenRight = r - q ; //noticefor(i = 0 ; i < nLeft ; ++i ){L[i] = A[p+i] ;}for(j = 0 ; j < nRight ; ++j){R[j] = A[q+j+1] ;  //notice}i = 0 ;j = 0 ;for(k = p ; k < r && i<nLeft && j<nRight ; k++ ){if(L[i] <= R[j]){A[k] = L[i] ; i++ ;}else{nTotalInversion += nLeft - i ;  //hereA[k] = R[j] ; j++ ;}}if(i >= nLeft){for(; k <= r ; ++k,++j) {A[k] = R[j] ;}}else{for(; k <= r ; ++k,++i){A[k] = L[i] ;}}}

 

練習題6.5-8

大概思路:先利用每個鏈表的頭元素來建立一個最大堆或者最大堆,然後再做類似堆排序的操作。但是這裡要注意的是用到了額外空間數組B來儲存排序後的元素。而且在交換樹根和堆的最後一個元素之後,還要檢查鏈表是否為空白,從而更新heap-size[A]的值。時間複雜度:O(nlgk)

 

虛擬碼實現:

 K-Road-MegerSort(A,k,n){BuildMinHeap(A,k) ; //use the K List's first data to build the heapi <- n ;j <- 0 ;nHeapSize <- k ;while i > 0do B[j] <- A[1]->data ;   j <- j + 1 ;    if A[1]->next = NULL  //if the one List is empty.     then  exchange  A[1] <-> A[nHeapSize] ;     nHeapSize <- nHeapSize - 1 ;  MinHeapify(A,1) ;   else then  MinHeapify(A,1) ;    i <- i - 1 ;  }

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.