老生常談 分治法與歸併排序

2021-07-10 10:49:12 字數 2407 閱讀 4743

首先來決乙個基本的問題:如何合併兩個有序序列?

同樣,我們也採取圖形演示的方法,來一步一步解決問題,假設我們現在存在兩個有序序列:1,3,5和2,4,6,7.

那麼我們首先應該在腦海中畫出這樣的一副圖形:

到現在,我們已經有解決問題的思路了:

比較這兩個序列的第乙個元素,誰較小就輸出誰,,然後將較小的元素從原佇列刪除.如此往下進行,如果某個隊列為空,則直接將另乙個佇列中元素依序輸出就好.

按照上面的思路,整個過程用圖形演示:

1. 選取較小元素

2. 選取較小元素

3. 選取較小元素

4. 選取較小元素

5. 選取較小元素,此時佇列arr1已經為空了,因此後面只需要依次輸出arr2中的元素即可

6. 輸出元素

7. 輸出元素

到現在整個過程已經描述清楚了.在具體的**實現過程中,刪除操作可以用移動下標來實現(許多操作,其實換個角度來想的)

**實現為:

public static void merge(int arr, int start, int

mid, int

end, int temp) else

}while (i <= m)

while (j <= n)

for (i = 0; i < z; i++)

arr[start + i] = temp[i];

}

現在我們來總結一下:兩個有序佇列可以很容易的合併成乙個有序佇列,合併的效率也是比較高的,可以達到o(n).

反向思考一下,任何乙個序列(n>1)都可以被拆分成兩個子串行,如果這兩個子串行是有序的,那麼可以很容易的將這兩個子串行合併成有序序列。

ok,現在我們來回憶一下分治法:

把乙個複雜的問題分成兩個或更多的相同或相似的子問題,再把子問題分成更小的子問題……直到最後子問題可以簡單的直接求解,原問題的解即子問題的解的合併。

結合我們剛才思考的,我們可以設想:任何乙個序列(n>1),都可以不斷的被一分為二,直到最後的序列中只有乙個元素,只有乙個元素的序列當然是有序的。

現在我們已經有一種排序的新思路了:為了讓原始序列arr有序,可將它分成a,b兩個序列,為讓a,b兩個序列有序,可以繼續將a序列拆成a1,a2兩個序列,如此拆分下去,直到序列中只有乙個元素。對於b序列也是同樣的操作。拆分完畢之後,再合併相近的兩個序列就行。

恭喜你,一步一步找到一種排序的新思路——歸併排序。現在我們要做的就是通過遞迴分解數列,然後通過合併就可以完成歸併排序了。

實現**如下:

public

class mergesort ;

int temp = new

int[arr3.length];

sort(arr3, 0, arr3.length - 1, temp);

for (int i = 0; i < temp.length; i++)

}public static void sort(int arr1, int start, int

end, int temp)

}public static void merge(int arr, int start, int

mid, int

end, int temp) else

}while (i <= m)

while (j <= n)

for (i = 0; i < z; i++)

arr[start + i] = temp[i];}}

老生常談比較排序之歸併排序 遞迴

歸併排序裡運用到演算法裡很重要的乙個思想 分治法 將原問題分解為幾個規模較小但r tyo類似於原問題的子問題 演算法導論 在每一層遞迴中都有3個步驟 1.分解問題 2.解決問題 3.合併問題的解 舉例待排序陣列 將它原始序列做分解。可以經過不斷的遞迴分解可以看到已經把原始陣列序列不斷分解為最小單位,...

分治法與歸併排序

分解 將原問題分解成一系列子問題 解決 遞迴地求解各子問題。若子問題足夠小,則直接求解 合併 將子問題的結果合併成原問題的解。歸併排序 合併排序 歸併排序的關鍵在於歸併兩個相鄰的子串行,使其變成乙個排序好的新序列。如果這個新序列就是原來需要進行排序的陣列,那麼排序完成。所以,我們需要將原序列遞迴地分...

老生常談 與equals的區別

最近在研究string,看到面試題有一題是 與equals的區別的題目。關於 與equals的區別相信大家很熟悉了,包括我也看到也是腦中一閃而過,比較的是位址,equals比較的是內容。真是這樣嗎?或者說能具體或深入的解釋下嗎?如果被面試官這樣問,會如何作答呢?由於最近看了string和object...