歸併排序
今天帶來的依舊是算法作業系列之🐢病排序(🐢:???)
哦說錯了,是歸併排序,我們老師的課件上也叫合併排序,下面是某度的百科的定義。
定義
歸併排序(MERGE-SORT)是建立在歸併操作上的一種有效的排序算法,該算法是採用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱爲二路歸併。歸併排序是一種穩定的排序方法。
既然建立在歸併操作上,那麼什麼是🐢病操作呢?
將兩個順序序列合併成一個順序序列的方法。這就是歸併操作了。
分析
既然歸併操作是講兩個順序序列合併成一個順序序列,那麼也就是說,歸併排序其實也就是通過不斷的進行歸併操作,使得序列從局部有序逐漸變爲整體有序的一個排序過程。
那麼我們就可以想象整個過程了。
給一個序列a,我們先將其不斷二分,直到最小,然後將相鄰兩個序列進行序列之間排序、合併,並複製到a的對應範圍內。
從局部有序,一點一點就到整體有序了。
代碼
遞歸
/*
* @Title mergeSort
* @Description 遞歸歸併排序
* @author 滑技工廠
* @Date 2020/3/17
* @param [a, left 左指針, right 右指針]
* @return void
* @throws
*/
public static void mergeSort(int a[], int left, int right) {
if (left < right) {//劃分的持續條件
//找到中間指針
int i = (left + right) / 2;
//一個序列分爲左右兩邊,分別進行mergesort,然後還會繼續劃分,
// 直到形成一個元素一個序列的情況,就可以序列之間排序merge了
mergeSort(a, left, i);
mergeSort(a, i + 1, right);
//序列排序併合併到b,left、i、right來進行劃分左右序列
int[] b = new int[right - left + 1];
merge(a, b, left, i, right);
copy(a, b, left, right);
}
}
這裏只給出歸併排序的思路,至於merge和copy方法詳情請見我的GitHub
非遞歸
public static void mergeSort2(int[] arr) {
if (arr == null || arr.length <= 0)
return;
int width = 1;
while (width < arr.length) {
mergePass(arr, width);
width *= 2;
}
}
private static void mergePass(int[] arr, int width) {
int start = 0;
while (start + 2 * width - 1 < arr.length) {
int mid = start + width - 1;
int end = start + 2 * width - 1;
merge2(arr, start, mid, end);
start = start + 2 * width;
}
//剩餘無法構成完整的兩組也要進行處理
if (start + width - 1 < arr.length)
merge2(arr, start, start + width - 1, arr.length - 1);
}
private static void merge2(int[] arr, int start, int mid, int end) {
int i = start;
int j = mid + 1;
int[] temp = new int[end - start + 1];
int index = 0;
while (i <= mid && j <= end) {
if (arr[i] <= arr[j])
temp[index++] = arr[i++];
else
temp[index++] = arr[j++];
}
while (i <= mid)
temp[index++] = arr[i++];
while (j <= end)
temp[index++] = arr[j++];
for (int k = start; k <= end; k++)
arr[k] = temp[k - start];
}
不知道爲什麼這篇閱讀量這麼少,幾天了還是4個,裏面還有我反覆看的。。。。莫非真是因爲這篇是我在交作業日期之後發的????