歸併排序演算法

2021-07-27 10:33:43 字數 2288 閱讀 4255

歸併排序以o(n logn)最壞情形時間執行而所使用的比較次數幾乎是最優的。它是分治演算法的乙個很好的例項。

首先我們使用分治模式分析排序問題

分解:分解待排序的n個元素的表成各具n/2個元素的子表

解決:使用歸併排序遞迴地排序兩個子表

合併:合併兩個已排序好的子表以產生已排序的答案

分解

因為當表長度n為1時無法再分,所以我們將n=1作為遞迴過 程的基準情形,當待排序的表長度為1時開始回公升,這種情況下我們不需要進行操作,因為長度為1的表已經排好序

這些子表的表可以表示成平衡二叉樹,根為原表,每個節點是當前表,每個左孩子是這個這個表的前半部分,每個右孩子是這個表的後半部分,為了方便,我們在n為奇數的情況下,將中間數歸位左孩子

這樣,當n為1時我們就訪問到了這個平衡二叉樹的葉

解決

合併成對的子表,因為兩個表都是按照公升序排列的,對他們進行歸併後產生的表也是公升序的

合併當訪問到葉並進行合併後,開始向上回公升,不斷地歸併當前節點的兩個子節點,最後完成整個表的排序,這裡對應的是樹的遍歷中的後續遍歷

procedure mergesort(l=[a[0]..a[n]])

/*l以非降序排列*/

if n>1

then

mid:=⌊n/2⌋

l1:=l[a[0]..a[mid]]

l2:=l[a[mid]..a[n]]

mergesort(l1)

mergesort(l2)

merge(l1,l2)

在歸併(merge)例程中,我們需要借助乙個佇列來儲存歸併結果,否則原表會發生損壞。我們來分析一下在歸併例程中不斷申請佇列的後果:

當我們訪問到葉時開始回公升,在葉處無需操作所以沒有申請記憶體的操作

每當我們訪問到節點時,我們申請在每一層我們都需要申請總長度為n的記憶體空間

在depth-1層,我們需要執行n/2次malloc操作,在depth-2層,我們需要執行n/4次malloc操作,依此類推,當我們訪問到根時,仍需執行一次malloc操作,總的malloc操作次數為n-1次!

而為了防止記憶體冗餘,我們又將執行n-1次free操作,這將產生很大的時間開銷,這是我們所不願意看見的

然而我們不難發現,對於任意一次歸併操作,即使是到了根節點,我們所需要的佇列大小仍未超過n,所欲我們只需要申請一次佇列,以[1..n]為有效長度,即可滿足我們的需求

//執行遞迴操作的函式主體

void mergesort(int*begin,int len,int*tmp)

}

歸併排序的主題已經完成,接下來討論merge例程引理:對兩個排好序的表進行歸併,最多隻需要n+m-1次比較

因為我們這兩個表是由乙個長度為2n的表產生,所以我們最多隻需要2n次比較即可完成歸併操作,而且我們可以僅將這個兩個表的父表作為引數,通過下標進行分割,而不產生額外的操作值得注意的是,因為這兩個表都是非降序表,所以若左表的最大元素的數值小於右表的最小值,則表示表已有序,無需操作;若右表的最大值小於左表的最小值,則只需要置換兩表的位置即可

void merge(int*begin,int len,int*tmp)elseelse

if(j==len)

//不斷向佇列中插入較小的元素

tmp[k++]=(begin[i]}}

//將排好序的佇列中的元素放回原表

for(i=0;ibegin[i]=tmp[i];

}

當然,對於使用來說,在每次使用之前需要做準備工作,這對使用來說是不友好的,所以我們需要些乙個輔助函式來封裝起來這些準備工作

//我們排序所使用的介面

bool mergesort(int*arr,int len)

mergesort(arr, len, tmp);//開始呼叫排序的函式主體

free(tmp);

return

true;

}

歸併演算法 歸併排序

歸併演算法 歸併排序 這周需要用到歸併演算法,於是找了找相關的資料,整理如下 歸併排序 merge sort 是利用 歸併 技術來進行排序。歸併是指將若干個已排序的子檔案合併成乙個有序的檔案。兩路歸併演算法 1 演算法基本思路 設兩個有序的子檔案 相當於輸入堆 放在同一向量中相鄰的位置上 r low...

歸併排序演算法

include stdafx.h include include include 合併兩段已經排好序的列表 void merge int list int mergelist int left int mid int right else if i mid else 將列表list按照seglen分...

歸併排序演算法

這個演算法感覺比插入難理解一些,下面說說我的理解 歸併排序的步驟 1.把長度為n的序列分為兩個長度為n 2的子串行 2.對這兩個子串行分別採用歸併排序 3.將兩個子串行合併成乙個最終的排序序列 通過步驟2可看到 在歸併排序中又用了歸併排序,可見這是乙個遞迴的過程。例如乙個陣列 a 8 下面採用遞迴排...