你們好,我是阿濠,今篇內容跟你們分享的是排序算法之歸併排序,很高興分享到segmentfault與你們一塊兒學習交流,初次見面請你們多多關照,一塊兒學習進步.
歸併排序(MERGE- SORT)是利用歸併的思想實現的排序方法
,該算法採用經典的分治
( divide- and-conquer)策略
(分治法將問題分(divide)成一些小的問題而後遞歸求解
,而治(conquer)的階段則將分的階段獲得的各答案修補」在一塊兒
,即分而治之)。算法
1.把數組從中間劃分紅兩個子數組
;
2.一直遞歸
地把子數組劃分
成更小的子數組
,直到子數組
裏面只有一個元素
3.依次按照遞歸的返回順序
,不斷地合併排好序的子數組
,直到最後把整個數組的順序排好
。segmentfault
看看治階段
,咱們須要將兩個已經有序
的子序列合併成一個有序序列
,好比上圖中的最後一次合併
,要將[4,5,7,8]和[1,2,3,6]
兩個已經有序的子序列
,合併爲最終序列[1,2,3,4,5,6,7,8]
,來看下實現步驟數組
//int arr[]={8,4,5,7,1,3,6,2}; //int temp[]=new int[arr.length]; //分解方法 public static void mergeSort(int[] arr, int left, int right, int[] temp) { if (left < right) { int mid = (left + right) / 2; //中間索引 //向左遞歸進行分解 //0 - mid 便是0 - 3 {8,4,5,7} mergeSort(arr, left, mid, temp); //向右遞歸進行分解 //mid+1 - midright 便是4 - 7 {1,3,6,2} mergeSort(arr, mid + 1, right, temp); } }
//合併的方法 /** * * @param arr 排序的原始數組 * @param left 左邊有序序列的初始索引 * @param mid 中間索引 * @param right 右邊索引 * @param temp 作中轉的數組 **/ public static void merge(int[] arr, int left, int mid, int right, int[] temp) { //初始化i,左邊有序序列的初始索引 int i = left; //初始化j,右邊有序序列的初始索引 //爲何要mid+1? //由於假設數組arr{1,3,5,6,2,4} mid=(left+right)/2 = 2 //此時左邊i=left mid左邊的就是 0 - mid 便是{1,3,5} //此時右邊就是mid+1 - right 便是{6,2,4} int j = mid+1; int t = 0;//指向temp數組的當前索引 //(-) //先把左右兩邊(有序)的數據按照規則填充到temp數組 //直到左右兩邊的有序序列,有一邊處理完畢爲止 //i <= mid 表明左邊有序序列有值 //j <= right 表明右邊有序序列有值 while (i <= mid & j <= right) {//繼續 //若是左邊的有序序列的當前元素,小於等於右邊有序序列的當前元素 //即將左邊的當前元素,拷貝到temp數組 //假設數組arr{1,3,5,6,2,4} //左邊 0 - mid 便是{1,3,5} //右邊 mid+1 -right 便是{6,2,4} //若arr[i]<= arr[j] 便是1 <= 6 if (arr[i] <= arr[j]) { temp[t] = arr[i];//temp[0]=arr[i]; t += 1;//指向temp數組下一位 i += 1;//指向左邊下一位arr[i+1]... }else{ //反之arr[i] >= arr[j] 左邊大於右邊 //則進行右邊賦值給temp數組 temp[t] = arr[j];//temp[0]=arr[i]; t += 1;//指向temp數組下一位 j += 1;//指向右邊邊下一位arr[j+1]... } } //(二) //把有剩餘數據的一邊的數據依次所有填充到temp //左邊的有序序列還有剩餘的元素,就所有填充到temp while( i <= mid){ temp[t] = arr[i]; t += 1; i += 1; } //右邊的有序序列還有剩餘的元素,就所有填充到temp while( j <= right){ temp[t] = arr[j]; t += 1; j += 1; } //(三) //將temp數組的元素拷貝到arr //爲何 t=0 ? //由於合併的時候按圖所示數組:{8,4,5,7,1,3,6,2} //最早進入的是84 left=0 right = 1 //通過上面的左邊與右邊比較,得出temp數組:4,8 // 此時清空指向temp數組的下標指針t 從新回到0 //tempLeft = 0 進行將temp數組裏的4,8 賦值給arr數組 t = 0; int tempLeft= left; while( tempLeft <= right){ arr[tempLeft]=temp[t]; t += 1;//賦值成功後指向temp數組的下標指針t日後移 tempLeft +=1;//84 完成後到57 此時left=2 right = 3 ... } }
//int arr[]={8,4,5,7,1,3,6,2}; //int temp[]=new int[arr.length]; //mergeSort(arr,0,arr.length-1,temp); //System.out.println("並歸排序後"+ Arrays.toString(arr)); //分解方法 public static void mergeSort(int[] arr, int left, int right, int[] temp) { if (left < right) { int mid = (left + right) / 2; //中間索引 //向左遞歸進行分解 //0 - mid 便是0 - 3 {8,4,5,7} mergeSort(arr, left, mid, temp); //向右遞歸進行分解 //mid+1 - midright 便是4 - 7 {1,3,6,2} mergeSort(arr, mid + 1, right, temp); //進行合併 merge(arr,left,mid,right,temp); } } 運行結果以下: tempLeft:0 rigth:1 tempLeft:2 rigth:3 tempLeft:0 rigth:3 tempLeft:4 rigth:5 tempLeft:6 rigth:7 tempLeft:4 rigth:7 tempLeft:0 rigth:7 並歸排序後[1, 2, 3, 4, 5, 6, 7, 8]
歸併算法是一個不斷遞歸的過程
,假設
數組的元素個數是n
。
時間複雜度是T(n)的函數: T(n) = 2*T(n/2) + O(n)
ide
對於規模爲n的問題,一共要進行log(n)層
的大小切分
;每一層的合併複雜度
都是O(n)
;
因此總體的複雜度就是O(nlogn)
。函數
因爲合併n個元素
須要分配一個大小爲n的額外數組
,合併完成以後
,這個數組的空間就會被釋放
。學習