分治模型在每層遞迴時都有三個步驟:
歸併排序演算法完全遵循分治模式。直觀上其操作如下:
歸併排序演算法的關鍵操作是「合併」步驟中兩個已經排序序列的合併。我們通過乙個輔助過程merge(a, p, q, r)來完成合併,其中a是乙個陣列,p、q和r是陣列下標,滿足p≤q
≤r
p\leq q \leq r
p≤q≤
r。該過程假設子陣列a[p…q]和a[q+1…r]都已排好序。它合併這兩個子陣列形成單一的已排好序的子陣列並代替當前的子陣列a[p…r]。
過程merge需要θ(n
)\theta(n)
θ(n)
的時間,其中n=r-p+1是待合併元素的總數。它按以下方式工作。回到我們玩撲克牌的例子,假設桌子上有兩堆牌面朝上的牌,每堆都已排好序,最小的牌在頂上。我們希望這兩堆牌合併成單一的排好序的輸出堆,牌面朝下地放在桌子上。
我們的基本步驟包括在牌面朝上的兩堆牌的頂上兩張牌中選取較小的一張,將該牌從其堆中移開(該堆的頂上將顯露一張新牌)併牌面朝下地將該牌放置到輸出堆。重複這個步驟,直到乙個輸出堆為空,這時,我們只是拿起剩餘的輸入堆並牌面朝下地將該堆放置到輸出堆。因為我們只是比較頂上的兩張牌,所以計算上每個基本步驟需要常量時間。因為我們最多執行n個基本步驟,所以合併需要θ(n
)\theta(n)
θ(n)
的時間。
下面的偽**實現了上面的思想,但有乙個額外的變化,以避免在每個基本步驟必須檢查是否堆有空。在每個堆的底部放置一張哨兵牌,它包含乙個特殊的值,用於簡化**。這裡,我們使用無窮大作為哨兵值,結果每當顯露一張值為無窮大的牌,它不可能為較小的牌,除非兩個堆都已顯露出其哨兵牌。但是,一旦發生這種情況,所有非哨兵牌都已被放置到輸出堆。因為我們事先知道剛好r-p+1張牌被放置到輸出堆,所以一旦已執行r-p+1個基本步驟,演算法就可以停止。
merge
(a, p, q, r)
n1 = q - p +
1n2 = r - q
let l[
1..n1+1]
and r[
1..n2+
1] be new arrays
for i =
1 to n1
l[i]
= a[p + i -1]
for j =
1 to n2
r[j]
= a[q + j]
l[n1+1]
= 無窮大
r[n2+1]
= 無窮大
i =1
j =1
for k=p to r
if l[i]
<= r[j]
a[k]
= l[i]
i = i +
1else a[k]
= r[j]
j = j +
1
從merge的偽**中可以發現,時間複雜度為θ(n
)\theta(n)
θ(n)
,空間複雜度為θ(n
)\theta(n)
θ(n)
,因為需要n個額外空間進行資料的重排。
現在我們可以把過程merge作為歸併排序演算法中的乙個子程式來用。下面的過程merge-sort(a, p, r)排序子陣列a[p…r]中的元素。若p≥r
p\geq r
p≥r,則該子陣列最多有乙個元素,所以已經排好序。否則,分解步驟簡單地計算乙個下標q,將a[p…r]分成兩個子陣列a[p…q]和a[q+1…r],前者包含⌊n/
2⌋
\left \lfloor n/2 \right \rfloor
⌊n/2
⌋個元素,後者包含⌊n/
2⌋
\left \lfloor n/2 \right \rfloor
⌊n/2
⌋個元素。
merge-
sort
(a, p, r)
if p < r
q =(p+r)
/2(向下取整)
merge-
sort
(a, p, q)
merge-
sort
(a, q+
1, r)
merge
(a, p, q, r)
c++**實現:
#include
#include
#include
using
namespace std;
void
merge
(vector<
int>
& arr,
int p,
int q,
int r)
l.push_back
(int_max)
;for
(int j=
1;j<=n2;j++
) r.
push_back
(int_max)
;int i =0;
int j =0;
for(
int k=p;k<=r;
++k)
else}}
void
merge_sort
(vector<
int>
& arr,
int p,
int r)
}int
main()
merge_sort
(arr,
0,n-1)
;for
(int i =
0; i < arr.
size()
; i++
)return0;
}
python**實現
def
merge_sort
(collection)
:def
merge
(left, right)
: result =
while left and right:
(left if left[0]
<= right[0]
else right)
.pop(0)
)return result + left + right
iflen(collection)
<=1:
return collection
mid =
len(collection)//2
return merge(merge_sort(collection[
:mid]
), merge_sort(collection[mid:])
)if __name__ ==
"__main__"
: user_input =
input
("enter numbers separated by a comma:\n"
).strip(
) unsorted =
[int
(item)
for item in user_input.split(
",")
]print
(*merge_sort(unsorted)
, sep=
",")
資料結構 歸併排序
排序 sort 或分類 內部排序方法可以分為五類 插入排序 選擇排序 交換排序 歸併排序和分配排序。歸併排序 include using namespace std 歸併排序中的合併演算法 void merge int a,int left,int center,int len int t int ...
資料結構 歸併排序
歸併排序,即merge sort,通過遞迴式的merge操作 merge即歸併 實現排序。演算法思想是分治思想 divide and conquer 歸併排序一般是遞迴實現的 時間複雜度o nlgn 遞迴都是一去一回,去的時候divide,回的時候conquer。表達欠提煉 1 divide,分 遞...
資料結構 歸併排序!!!
歸併排序 整體思想 將資料分成很多的部分,每次排序資料的一部分,然後將兩部分的資料進行整體排序,這樣一步一步將整體資料排序。如圖 注 將需要排序的資料進行分塊,當每個塊的資料足夠的少的時候就可以進行效率高的排序方法,當兩塊資料排序好的時候就可以將兩塊排序好的資料進行合併。具體實現方法 ifndef ...