今天來搞一搞歸併(合併)排序
基本思想
歸併排序的主要實現思想是分治策略,
先拋出兩個問題,大家在讀的過程中分析下爲什麼歸併排序滿足下面這兩點
1、時間複雜度:T(n)= O(nlogn)
2、合併排序算法是漸進最優算法。
將待排序的數組分爲大致相等的兩部分,分別對這兩部分進行排序,最終將兩個排好序的數組合併成一個有序的數組。
接下來我們先來看實現代碼,如果可以看明白代碼,說明你已經瞭解了歸併算法了。看的時候有疑問也不要緊,我們下面會進行詳細的分解詳細描述。
代碼實現(遞歸)
/**
* 歸併排序(遞歸寫法)
* @param nums 需要排序的數組
* @param left 需排序的起始下標
* @param right 需排序的結束下標
* @return 結果(有序數組)
*/
public int[] mergeSort(int[] nums,int left,int right){
//如果 數組爲空或者數組的元素數爲1,則認爲該數組已經是有序的
if(left < right){
//1、找數組中間位置下標
int mid = (left + right)/2;
//2、對左半部分排序
mergeSort(nums,left,mid);
//3、對有右半部分排序
mergeSort(nums,mid+1,right);
//4、合併
merge(nums,left,mid,right);
}
return nums;
}
/**
* 兩個有序數組合並
* @param nums 原數組
* @param left 數組起始下標
* @param mid 數組中間下標
* @param right 數組結束下標
*/
public void merge(int[] nums,int left,int mid,int right){
//1、數組一的起始下標
int i = left;
//2、數組二的起始下標
int j = mid +1;
//3、需要一個臨時數組
int[] temp = new int[right - left +1];
int k = 0;
//4、順序比較兩個數組,並將小的值放到臨時數組中,直到其中一個數組中的元素都放入臨時數組中
while (i<=mid && j<=right){
if(nums[i] <= nums[j]){
temp[k++] = nums[i++];
}else {
temp[k++] = nums[j++];
}
}
//5、將數組一剩餘的元素放入臨時數組
while (i<=mid ){
temp[k++] = nums[i++];
}
//6、將數組二剩餘的元素放入臨時數組
while (j<=right){
temp[k++] = nums[j++];
}
//7、將臨時數組中的元素copy到原數組中
for (int l = 0; l < temp.length; l++) {
nums[left+l] = temp[l];
}
}
上面註釋已經將步驟一一都寫了,如果有疑問我們看下詳細的圖解
大家可以思考下 非遞歸方式如何實現,以及自然合併排序算法
注:自然合併排序會在下篇文章中介紹,
參考
算法設計與分析 第3版__王曉東編著_北京:清華大學出版社_P330_2014.02_13476624