日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

排序算法 --- 歸并排序

 貪挽懶月 2022-06-20 發(fā)布于廣東

一、排序思想

歸并排序是采用分治算法,即將一個(gè)大問題切分成一些小問題然后遞歸求解。歸并排序的圖解如下:

歸并思路

分的過程簡單,就是將數(shù)組拆開來,拆到每組只有一個(gè)元素為止。治的過程是怎么排序的呢?以最后一次治為例,即將4 5 7 81 2 3 6合并成最終的有序序列為例,看看如何實(shí)現(xiàn)。

  • 首先創(chuàng)建一個(gè)新的數(shù)組tempArr,長度為要進(jìn)行“治”的兩個(gè)數(shù)組長度之和;
  • 然后用i指向4,即第一個(gè)數(shù)組的最左邊,j指向1,即第二個(gè)數(shù)組的最左邊;
  • 發(fā)現(xiàn)41大,那么就將1存入tempArr,同時(shí)指針j后移;
  • 繼續(xù)比較指針ij所指元素的大小,發(fā)現(xiàn)24小,將2存入tempArr,同時(shí)j繼續(xù)后移;
  • 繼續(xù)比較,將3存入tempArr,j繼續(xù)后移;
  • 此時(shí)發(fā)現(xiàn)64大,就將4存入tempArr,同時(shí)i后移;
  • 56小,將5存入tempArr,i繼續(xù)后移;
  • 76大,將6存入tempArr,此時(shí)j已經(jīng)處于最后了,不能后移了;
  • 接著就將i所指的剩余元素都存入tempArr,這個(gè)tempArr就是有序的了。

二、代碼實(shí)現(xiàn)

1. 第一種方式:

這種方式很容易懂,我們先不是要拆分?jǐn)?shù)組嗎?那就拆唄,拆到什么時(shí)候?yàn)橹鼓??拆出來的?shù)組只有一個(gè)元素了那就不用拆了。

  • 拆分:
public static int[] sort(int[] arr) {
 if (arr == null || arr.length == 1) {
  return arr;
 }
 // 拆分?jǐn)?shù)組
 int mid = arr.length / 2; // 中間指針,利用該指針將數(shù)組拆分
 int[] left = Arrays.copyOfRange(arr, 0, mid);
 int[] right = Arrays.copyOfRange(arr, mid, arr.length);
 // 調(diào)用合并方法,因?yàn)閘eft和right可能可以再拆分,所以傳進(jìn)去的left和right再遞歸調(diào)用當(dāng)前方法
 return merge(sort(left), sort(right));
}
  • 合并:該方法傳入兩個(gè)數(shù)組,對數(shù)組進(jìn)行合并上面已經(jīng)講了思路,按照思路來寫就好了:
public static int[] merge(int[] left, int[] right) {
 // 定義臨時(shí)數(shù)組
 int[] tempArr = new int[left.length + right.length];
 // 定義兩個(gè)指針
 int i = 0; // left的指針
 int j = 0; // right的指針
 // 進(jìn)行合并操作
 for(int index=0; index < tempArr.length; index ++) {
  // 如果left的遍歷完了,那么將right中的剩余元素全部依次放入tempArr中
  if (i >= left.length) {
   tempArr[index] = right[j];
   j++; // 指針后移
  } else if(j >= right.length) {
   // 如果right遍歷完了,那么將left中剩余的元素全部依次放入tempArr中
   tempArr[index] = left[i];
   i++; // 指針后移
  } else if (left[i] < right[j]) {
   // 如果i所指的數(shù)更小,就將該數(shù)存入tempArr
   tempArr[index] = left[i];
   i++; // 指針后移
  } else {
   // 如果j所指的數(shù)大于等于i所指的數(shù),就將j所指的數(shù)存入tempArr
   tempArr[index] = right[j];
   j++; // 指針后移
  }
 }
 return tempArr;
}

沒錯(cuò),這樣就搞定了,這就是完全按照上面案例分析來做的,不過缺點(diǎn)就是,拆分的時(shí)候,是真正的拆除兩個(gè)數(shù)組來了,會(huì)浪費(fèi)空間,優(yōu)點(diǎn)就是容易理解。

2. 第二種方式:

第二種方式就是不真正的將數(shù)組拆成兩部分,而是通過一個(gè)中間索引mid,將數(shù)組標(biāo)識(shí)成兩部分。這樣就不需要真正的拆分,不會(huì)浪費(fèi)空間,但是代碼相對來說更難理解。

  • 合并:先看合并部分,除了原始數(shù)組外,還有三個(gè)參數(shù),leftmid構(gòu)成左邊的數(shù)組,mid+1right構(gòu)成右邊的數(shù)組,只要理解了這一點(diǎn),下面的代碼就容易理解了。
public static void merge(int[] arr, int left, int mid, int right) {
 // 定義臨時(shí)數(shù)組
 int[] tempArr = new int[right - left + 1]; 
 int i = left; // 左邊數(shù)組的指針
 int j = mid + 1; // 右邊數(shù)組的指針
 int k = 0; // 臨時(shí)數(shù)組的指針
 // 當(dāng)左邊數(shù)組和右邊數(shù)組都還沒遍歷完的時(shí)候
 while(i <= mid && j <= right) {
  // 如果i所指的元素更小,就其放入tempArr,同時(shí)i后移
  if (arr[i] <= arr[j]) {
   tempArr[k++] = arr[i++];
  } else {
   // 如果j所指的更小,就將其放入tempArr,同時(shí)j后移
   tempArr[k++] = arr[j++];
  }
 }
 // 如果左邊的數(shù)組還沒遍歷完,就將左邊數(shù)組剩余元素依次放入tempArr中
 while (i <= mid) {
  tempArr[k++] = arr[i++];
 }
 // 如果右邊的數(shù)組還沒遍歷完,就將右邊數(shù)組剩余元素依次放入tempArr中
 while (j <= right) {
  tempArr[k++] = arr[j++];
 }
 // 將tempArr中排好序的添加到原數(shù)組中
 for(int x=0; x<tempArr.length; x++) {
  arr[left + x] = tempArr[x];
 }
}
  • 拆分:拆分到什么時(shí)候?yàn)橹鼓?,如?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(71, 193, 168);">left和right相等了,表示只有一個(gè)元素,那就不用拆了,否則就對左邊和右邊的都進(jìn)行遞歸拆分,拆到不可再拆就合并。
public static void sort(int[] arr, int left, int right) {
 // 如果左指針和右指針相等,表示只有一個(gè)元素,那就不需要拆分了
 if (left == right) {
  return;
 }
 // 否則就進(jìn)行拆分
 int mid = left + (right - left) / 2; // 找到中間值進(jìn)行拆分
 // 對左邊再進(jìn)行拆分
 sort(arr, left, mid);
 // 對右邊再進(jìn)行拆分
 sort(arr, mid+1, right);
 // 進(jìn)行合并
 merge(arr, left, mid, right);
}

經(jīng)測試,對1000萬個(gè)隨機(jī)數(shù)進(jìn)行排序,大概需要2秒,方式一和方式二時(shí)間上差不多,但是方式二可以省不少的內(nèi)存,大家可以在執(zhí)行的時(shí)候看看內(nèi)存的占用情況。

-java開發(fā)那些事-

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請遵守用戶 評(píng)論公約

    類似文章 更多