從前面已經講解了冒泡排序、選擇排序、插入排序,快速排序了,本章主要講解的是歸併排序,但願你們看完可以理解並手寫出歸併排序快速排序的代碼,而後就經過面試了!若是我寫得有錯誤的地方也請你們在評論下指出。html
來源百度百科:面試
歸併排序(MERGE-SORT)是創建在歸併操做上的一種有效的排序算法,該算法是採用分治法(Divide and Conquer)的一個很是典型的應用。將已有序的子序列合併,獲得徹底有序的序列;即先使每一個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱爲二路歸併。算法
過程描述:數組
歸併過程爲:比較a[i]和b[j]的大小,若a[i]≤b[j],則將第一個有序表中的元素a[i]複製到r[k]中,並令i和k分別加上1;不然將第二個有序表中的元素b[j]複製到r[k]中,並令j和k分別加上1,如此循環下去,直到其中一個有序表取完,而後再將另外一個有序表中剩餘的元素複製到r中從下標k到下標t的單元。歸併排序的算法咱們一般用遞歸實現,先把待排序區間[s,t]以中點二分,接着把左邊子區間排序,再把右邊子區間排序,最後把左區間和右區間用一次歸併操做合併成有序的區間[s,t]。微信
原理:ide
歸併操做的工做原理以下:優化
第一步:申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列spa
第二步:設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置debug
第三步:比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置指針
重複步驟3直到某一指針超出序列尾
將另外一序列剩下的全部元素直接複製到合併序列尾
下面我就來作個小小的總結:
如今我有兩個已經排好順序的數組:int[] arr1 = {2, 7, 8}
和int[] arr2 = {1, 4, 9}
,我還有一個大數組來裝載它們int[] arr = new int[6];
那麼,我將兩個數組的值進行比較,誰的值比較小,誰就放入大數組中!
首先,拿出arr1[0]
和arr2[0]
進行比較,顯然是arr2[0]
比較小,所以將arr2[0]
放入大數組中,同時arr2
指針日後一格
因此,如今目前爲止arr = {1}
隨後,拿arr1[0]
和arr2[1]
進行比較,顯然是arr1[0]
比較小,將arr1[0]
放入大數組中,同時arr1
指針日後一格
因此,如今目前爲止arr = {1,2}
隨後,拿arr1[1]
和arr2[1]
進行比較,顯然是arr2[1]
比較小,將arr2[1]
放入大數組中,同時arr2
指針日後一格
因此,如今目前爲止arr = {1,2,4}
........
遍歷到最後,咱們會將兩個已排好序的數組變成一個已排好序的數組arr = {1,2,4,7,8,9}
從上面的演算咱們就直到,歸併排序的前提是須要兩個已經排好順序的數組,那每每不會有兩個已經排好順序的數組給咱們的呀**(通常是雜亂無章的一個數組)**,那這個算法是否是很雞肋的呢??
其實並非的,首先假設題目給出的數組是這樣子的:int[] arr = {2, 7, 8, 1, 4, 9};
當咱們要作歸併的時候就以arr[3]
也就元素爲1的那個地方分開。是而後用一個指針L
指向arr[0]
,一個指針M
指向arr[3]
,用一個指針R
指向arr[5]
(數組最後一位)。有了指針的幫助,咱們就能夠將這個數組切割成是兩個有序的數組了(操做的方式就能夠和上面同樣了)
但是上面說了,通常給出的是雜亂無章的一個數組,如今仍是達不到要求。好比給出的是這樣一個數組:int[] arrays = {9, 2, 5, 1, 3, 2, 9, 5, 2, 1, 8};
此時,咱們就得用到分治的思想了:
int[] arr = {2, 7, 8, 1, 4, 9};
數組分隔成一份一份的,arr[0]
它是一個有序的"數組",arr[1]
它也是一個有序的"數組",利用指針(L,M,R)又能夠像操做兩個數組同樣進行排序。最終合成{2,7}
.......再不斷拆分合並,最後又回到了咱們的arr = {1,2,4,7,8,9}
,所以歸併排序是能夠排序雜亂無章的數組的這就是咱們的分治法--->將一個大問題分紅不少個小問題進行解決,最後從新組合起來
實現步驟:
........
public static void main(String[] args) { int[] arrays = {9, 2, 5, 1, 3, 2, 9, 5, 2, 1, 8}; mergeSort(arrays, 0, arrays.length - 1); System.out.println("公衆號:Java3y" + arrays); } /** * 歸併排序 * * @param arrays * @param L 指向數組第一個元素 * @param R 指向數組最後一個元素 */ public static void mergeSort(int[] arrays, int L, int R) { //若是隻有一個元素,那就不用排序了 if (L == R) { return; } else { //取中間的數,進行拆分 int M = (L + R) / 2; //左邊的數不斷進行拆分 mergeSort(arrays, L, M); //右邊的數不斷進行拆分 mergeSort(arrays, M + 1, R); //合併 merge(arrays, L, M + 1, R); } } /** * 合併數組 * * @param arrays * @param L 指向數組第一個元素 * @param M 指向數組分隔的元素 * @param R 指向數組最後的元素 */ public static void merge(int[] arrays, int L, int M, int R) { //左邊的數組的大小 int[] leftArray = new int[M - L]; //右邊的數組大小 int[] rightArray = new int[R - M + 1]; //往這兩個數組填充數據 for (int i = L; i < M; i++) { leftArray[i - L] = arrays[i]; } for (int i = M; i <= R; i++) { rightArray[i - M] = arrays[i]; } int i = 0, j = 0; // arrays數組的第一個元素 int k = L; //比較這兩個數組的值,哪一個小,就往數組上放 while (i < leftArray.length && j < rightArray.length) { //誰比較小,誰將元素放入大數組中,移動指針,繼續比較下一個 if (leftArray[i] < rightArray[j]) { arrays[k] = leftArray[i]; i++; k++; } else { arrays[k] = rightArray[j]; j++; k++; } } //若是左邊的數組還沒比較完,右邊的數都已經完了,那麼將左邊的數抄到大數組中(剩下的都是大數字) while (i < leftArray.length) { arrays[k] = leftArray[i]; i++; k++; } //若是右邊的數組還沒比較完,左邊的數都已經完了,那麼將右邊的數抄到大數組中(剩下的都是大數字) while (j < rightArray.length) { arrays[k] = rightArray[j]; k++; j++; } }
我debug了一下第一次的時候,就能夠更容易理解了:
上面的兩個步驟不斷循環,最後得出有序的數組:
來源:www.cnblogs.com/noKing/p/79…
我這裏整理一下要點,有興趣的同窗可到上面的連接上閱讀:
若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠關注微信公衆號:Java3y