2023年由馮諾依曼首次提出。
執行流程
1 不斷的將當前序列平均分割成兩個子串行
直到不能再分割(序列中只剩1個元素)
2 不斷的將兩個子串行合併成乙個有序序列
直到最終只剩下1個有序序列
歸併排序,主要有分和和兩個步驟。
其中,分感覺好理解些,找出begin,end,求出middle,然後遞迴呼叫,直到元素個數小於或等於1時,不再分割。不難寫出:
public
static
void
dividesort
(int
array,
int begin,
int end)
合併就有些許難度,這其實算是另外一道演算法題:
比如,我們需要將兩個有序陣列[3, 8]、[6, 10]合併成乙個大陣列。
大致流程是:
建立乙個可以容納兩個陣列長度的大陣列array,用以存放排序好的陣列。並設立乙個變數ai,用以存放新元素要存放的位置。預設是0;
設立兩個變數lefti、righti,分別指向兩個陣列當前比較到了**。預設都是0,也就是li = 0; ri = 0;
比較array1[li] 與array2[ri]值的大小
如果array1[li] <= array2[ri],則將array[ai] = array1[li]; li++;
如果li超過array1的邊界,則將array2剩餘的元素依次放在新陣列array後面。
如果array1[li] > array2[ri],則將array[ai] = array2[ri]; ri++;
如果ri超過array2的邊界,則將array1剩餘的元素依次放在新陣列array後面。
有了以上思路,不難寫出**:
public
static
void
main
(string[
] args)
;int
array2 =
;mergesortarray
(array1, array2);}
public
static
void
mergesortarray
(int
array1,
int[
] array2)
else}if
(li == array1.length)}if
(ri == array2.length)
}for
(int i =
0; i < array.length; i++)}
列印結果:12
2346
10
寫完了兩個不相關的陣列,我們再看一下歸併排序的合併。
歸併排序的兩個陣列是相連的,並且陣列大小是等分的,因此,在建立新的陣列時候,不需要建立乙個等長的大陣列。
只需要將前面乙個陣列copy出乙份,然後將新copy出來的陣列,與後面的陣列做對比,將比較出來的元素放入到原陣列中即可。這樣,空間複雜度比上面的少一半。
左邊先結束,什麼也不做
右邊先結束,左邊按個移過來
public
static
void
main
(string[
] args)
;dividesort
(array,
0, array.length)
;for
(int i =
0; i < array.length; i++)}
public
static
void
dividesort
(int
array,
int begin,
int end)
public
static
void
mergesort
(int
array,
int begin,
int middle,
int end)
//如果左邊還沒結束
while
(li < le)
else
}else
}//如果左邊先結束,則剩下的啥也不需要做了
}
其中,裡面的while迴圈可優化:
while
(li < le)
else
}
歸併排序花費時間
假設歸併排序花費的時間為t(n)
裡面有兩個均分的歸併排序t(n/2)
以及乙個合併遍歷o(n)
那麼,可以得出:
t(n) = 2*t(n/2) + o(n);…1
並且t(1) = o(1);
那麼1式左右同除以n
t(n)/n = 2*t(n/2)/n + o(1);
t(n)/n = t(n/2)*2/n + o(1);
t(n)/n = t(n/2)/n/2 + o(1);
令s(n) = t(n)/n;,那麼s(1) = t(1) = o(1);
s(n) = s(n/2)+ o(1) = s(n/4)+ o(2) = s(n/8)+ o(3) = s(n/2^k)+ o(k)
n = 2^k,k = logn
s(n) = s(2^k) = s(1) + o(logn) = o(logn)
s(n) = t(n)/n = o(logn)
那麼,t(n) = o(nlogn)
由於歸併排序總是平均分割子串行,所以最好、最壞、平均時間複雜度都是o(nlogn),屬於穩定排序。
歸併排序的空間複雜度為:
在分割的時候,由於是遞迴呼叫,每次遞迴需要占用記憶體空間,遞迴呼叫分割logn次,也就是分割是o(logn)
在合併的時候,由於需要將左邊的陣列copy出乙份,因此,占用空間是o(n/2)
所以,歸併排序的空間複雜度為o(logn + n/2) 約等於 o(n)
資料結構與演算法 歸併排序
include include include string include include include include algorithm using namespace std void merge vector input,int left,int mid,int right,vector...
資料結構與演算法(歸併排序)
歸併排序是採用分治法的乙個典型的應用,歸併排序的思想就是先遞迴分解陣列,在合併陣列。將陣列分解最小之後,然後合併兩個有序陣列,基本思路是比較兩個陣列的前面的數,誰小就先取誰,取了後相應的指標就往後移一位,直至乙個陣列為空,最後把另乙個陣列的剩餘部分複製過來即可。def merge sort alis...
資料結構與演算法 歸併排序
你可以在 的 mer 標籤中看到歸併排序的動畫。歸併排序 時間複雜度 o nlogn 空間複雜度 o n 基本思想 分治思想。8 6 2 3 1 5 7 4 分 8 6 2 3 1 5 7 4 分 8 6 2 3 1 5 7 4 分 8 6 2 3 1 5 7 4 並 8 6 2 3 1 5 7 4...