資料結構 歸併排序

2021-08-29 09:45:33 字數 3026 閱讀 5513

歸併排序(merge-sort)是利用歸併的思想實現的排序方法,該演算法採用經典的分治(divide-and-conquer)策略(分治法將問題分(divide)成一些小的問題然後遞迴求解,而治(conquer)的階段則將分的階段得到的各答案"修補"在一起,即分而治之)。歸併排序是乙個典型的一空間換取時間的排序方法,是一種穩定的排序演算法

可以看到這種結構很像一棵完全二叉樹,本文的歸併排序我們採用遞迴去實現(也可採用迭代的方式去實現)。分階段可以理解為就是遞迴拆分子序列的過程。

歸併的時間複雜度分析:主要是考慮兩個函式的時間花銷,

陣列劃分函式 merge();

有序陣列歸併函式mergesorted();

merge()函式的時間複雜度為o(n),因為**中有2個長度為n的迴圈(非巢狀),所以時間複雜度則為o(n);

簡單的分析下元素長度為n的歸併排序所消耗的時間 t[n]:呼叫merge()函式劃分兩部分,那每一小部分排序好所花時間則為t[n/2],而最後把這兩部分有序的陣列合併成乙個有序的陣列merges()函式所花的時間為o(n);

公式:t[n]  =  2t[n/2] + o(n); 因為不管元素在什麼情況下都要做這些步驟,所以花銷的時間是不變的,所以該演算法的最優時間複雜度和最差時間複雜度及平均時間複雜度都是一樣的為:o(nlogn )

因為在歸併有序序列的過程中使用了乙個大小是n的陣列,所以歸併排序的空間複雜度是o(n)。

陣列初始序列對歸併排序沒有影響。

與快速排序一樣,歸併排序也是基於分治策略的排序,(分治法將問題(divide)成一些小的問題然後遞迴求解,而治(conquer)的階段則將分的階段得到的各答案"修補"在一起,即分而治之)。歸併排序將待排序的元素分成兩個長度相等的子串行,分別為每乙個子串行排序,然後把子序列合併成乙個總的序列。合併兩個子串行的過程稱為二路歸併。(注:二路歸併演算法是一種穩定排序演算法,他的執行時間不依賴與待排元素的初始序列,因此也就避免了快速排序最差的情況),演算法時間複雜度

void mergesort(int *arr, int left, int right)

}void merge(int *arr, int left, int right, int mid)

while (i <= mid)//第乙個表沒有檢測完

while (j <= right)//第二個表沒有檢測完

for (int i = 0;i < s;i++)

arr[left + i] = array[i];

free(array);

}

我們可以把分解的過程理解為建立完全二叉樹的過程(遞迴深度是

在這裡給大家列出(2,4,7,5,8,1,3,6)這個序列歸併排序的過程,從圖中我們可以看到,每次都是在原有元素的基礎上面對半分,即取一半,直到分解為每一組元素剩下乙個為止,我們預設乙個元素已經有序,然後在依次把每兩個元素合併成乙個有序序列,即上圖中的第一步合併操作,從那裡我們可以看到現在已經合併為四個分組,每個分組裡面兩個元素有序排列,接著在進行一次合併,合併為兩個分組,每組四個元素有序排列,接著進行最後一次合併操作,整個序列變為有序,排序結束。

但是在實際上遞迴的歸併排序時間代價和空間代價都很高,應為要做多次遞迴呼叫,最多需要

//歸併排序的迭代演算法實現

void merge(int *arr1, int *arr2,int left, int right, int mid)

while (i <= mid)//第乙個表沒有檢測完

while (j <= right)//第二個表沒有檢測完 }

void mergepass(int *arr1, int *arr2, int len,int n)

if (i + len <= n)//特殊情況第二個歸併項不足len

else//特殊情況,只剩下乙個歸併項

for (int j = i;j <= n - 1;j++) }

void mergesort(int *arr, int n)

}

下面我們以乙個例項來演示迭代的歸併排序,初始序列是(21,25,49,25*,93,62,72,08,37,16,54)在這裡為了說明排序是穩定的,用了25*做對照,25和25*相對位置沒有變,所以歸併排序是穩定的。

len=1:21,25,49,25*,93,62,72,08,37,16,54

len=2:21 25,25* 49,62 93,08 72,16 37,54

len=4,:21 25 25* 49,08 62 72 93,16 37 54

len=8:08 21 25 25* 49 62 72 93,16 37 54

len=16:08 16 21 25 25* 37 49 54 62 72 93

當len=1時,我們把每個元素都看作歸併項,歸併為len=2的歸併項,每一次len都增大原來的二倍。假設陣列元素arr[0]到arr[n-1]已經歸併為長度為len的歸併項,要求再將這些歸併項兩兩歸併,歸併成長度為2len的歸併項,把這些歸併項放在arr2的輔助陣列中,如果n不是2len的整數倍,則歸併完一趟,可能遇到兩種情況:

(1)剩下乙個長度為len的歸併項和乙個長度小於len的歸併項,這時可以再次呼叫merge函式將他們歸併稱為乙個長度小於2len的歸併項。

(2)只剩下乙個歸併項,長度小於或者等於len,由於沒有另乙個歸併項與其歸併,可以將直接放到arr2的輔助陣列中,準備參加下一趟歸併操作。

總之,迭代演算法分為兩部分,第一部分先對長度為len的歸併項進行兩兩歸併,直到出現上述情況之一,第二部分處理上述特殊情況。

資料結構 歸併排序

排序 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 ...