分治法與歸併排序

2021-12-29 20:04:07 字數 2474 閱讀 5434

〉〉分解:將原問題分解成一系列子問題

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

〉〉合併:將子問題的結果合併成原問題的解。

歸併排序(合併排序)

歸併排序的關鍵在於歸併兩個相鄰的子串行,使其變成乙個排序好的新序列。如果這個新序列就是原來需要進行排序的陣列,那麼排序完成。所以,我們需要將原序列遞迴地分成若干子串行,直道最小的子串行只有乙個元素,然後將子串行依次歸併,就可以得到排序好的原序列。我們要解決的第乙個問題就是:假設有子串行a[p...q]和子串行[q + 1...r]是已經排序好的子串行,如何按順序將它們歸併到乙個子串行中去呢?

歸併兩個子串行

我們可以用撲克牌做模擬。將兩堆數量相近的撲克牌按順序疊好,最小的牌放在最上面,牌面朝上。

〉〉第一步:拿出兩張中較小的一張,放在桌上。

〉〉第二步:分別比較所拿的牌和兩個堆上面的牌,重複第一步,跟在前一張牌的後面。直到乙個堆拿完。

〉〉第三步:將剩餘的堆從上往下一次放在桌上,跟在前一張牌的後面。

由此可見,按問題要求(加橙色的),我們可以設計如下**:

void merge(int ar, int p, int q, int r, int temp)

while(i <= q) //如果ar[p..q]有剩

temp[k++] = ar[i++];

while(j <= r) //如果ar[q+1..r]有剩

temp[k++] = ar[j++];

for(k = 0; k <= (r - p); k++) //將合併後的子串行賦值給原序列ar[p...r]

ar[p + k] = temp[k];

}對於歸併排序,我們要解決的第二個問題就是:原序列如何成為有序序列?

利用分治策略使原序列有序

我們可以通過將原序列二分為兩個子串行,再將兩個子串行二分為另外的四個子串行,直到不能再分解為止。然後分別合併相鄰的兩個子串行,直到不能合併為止。這裡引用網路上的一張圖修改後來說明這個原理。

前面提到過,解決乙個給定問題,演算法需要一次或多次地遞迴呼叫自身來解決相關的子問題,這種演算法通常採用分治策略。所以,我們可以利用分治策略通過通過遞迴呼叫乙個函式來解決。我們可以這樣寫**:

void mergesort(int ar, int head, int end, int temp)

}分析上面的**,我們可以將上圖示上執行順序(建議在新視窗開啟下圖),來驗證該演算法的正確性。同時,你也可以通過類似「迴圈不變式」的方法證明:

完整**

到這裡,歸併排序的所有問題都解決完了。我們給出完整的不帶注釋(分配記憶體後的空注釋是標誌,提醒一定要及時釋放記憶體)的**。

1 #include

2 #include

3 #include

4 #include

5 6 void mergesort(int , int, int, int );

7 void merge(int , int, int, int, int);

8 9 int main(int argc, char * ar**)

23 24 mergesort(ar, 0, n - 1, temp);

25 26 printf("\n歸併排序後:\n");

27 for(i = 0; i < n; i++)

28 printf("%-4d",ar[i]);

29 30 free(temp);

31 free(ar);

32 33 _getch();

34 return 0;

35 }

36 37 void mergesort(int ar, int head, int end, int temp)

44 }

45 46 void merge(int ar, int p, int q, int r, int temp)

54 while(i <= q)

55 temp[k++] = ar[i++];

56 while(j <= r)

57 temp[k++] = ar[j++];

58 59 for(k = 0; k <= (r - p); k++)

60 ar[p + k] = temp[k];

61 }

mergesor

分治法,歸併排序

1.時間複雜度為o nlog n 非降序 package com.cn.insertion 歸併排序,採用分治法的策略 author administrator public class merge sort mergesort a,0,9 for int i 0 i a.length i 先分在和...

分治法(歸併排序)

分治法.cpp 定義控制台應用程式的入口點。include stdafx.h include include include define max 30 using namespace std int l max int r max void merge int a,int p,int q,int ...

分治法 歸併排序

歸併排序是分治法的典型應用,思想如下 divide divide the array to 2 subarray conquer reverse in 2 subarray,if only one elem return combine merge two ordered subarray t n ...