<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          歸并排序算法動(dòng)圖詳解,小白也能懂!Java實(shí)現(xiàn)

          共 6306字,需瀏覽 13分鐘

           ·

          2021-08-26 10:31

          歸并排序詳解(后序遍歷)

          大家可能都對(duì)二叉樹(shù)的后序遍歷比較熟悉,實(shí)際上歸并排序本質(zhì)框架就是二叉樹(shù)的后序遍歷,根結(jié)點(diǎn)的遍歷只不過(guò)換成了治(Merge方法的調(diào)用),本文將結(jié)合動(dòng)圖+代碼的方式進(jìn)行最通俗的講解。

          「基本思想」:利用歸并的思想實(shí)現(xiàn)的排序方法,該算法采用經(jīng)典的分治(divide-and-conquer)策略(分治法將問(wèn)題分(divide)成一些小的問(wèn)題然后遞歸求解,而治(conquer)的階段則將分的階段得到的各答案修補(bǔ)在一起,即分而治之)。

          分的過(guò)程

          下面自制配了一張動(dòng)圖來(lái)更好理解分的過(guò)程,其實(shí)完全就是左右根的后序遍歷,根的遍歷就是治(Merge方法的調(diào)用),分的過(guò)程中暫不可考慮根結(jié)點(diǎn)的遍歷,動(dòng)圖中僅展示左邊的分的過(guò)程,以mid將其分組,遞歸的終止條件就是left==right,每組的right和left都不相同,左邊遞歸調(diào)用傳值left的值不變,right值為mid,右邊遞歸調(diào)用傳值left為mid+1,因?yàn)閙id是左邊的最后一個(gè),所以要加1,右邊的值就是right。

          代碼如下:
          public static void mergeSort(int[] arr, int left, int right, int[] temp) {
              if (left != right) {//left和right的值會(huì)根據(jù)mid的值不斷變化
                  int mid = (left + right) / 2;
                  //向左遞歸進(jìn)行分解,動(dòng)圖分組中靠左的部分
                  mergeSort(arr, left, mid, temp);
                  //向右遞歸進(jìn)行分解  動(dòng)圖分組中靠右的部分
                  mergeSort(arr, mid + 1, right, temp);
                  //合并(相當(dāng)于根)下面動(dòng)圖中暫未表示合的思路
                  merge(arr, left, mid, right, temp);
              }
          }

          如下圖:「加上右邊邏輯上大致呈現(xiàn)二叉樹(shù)狀」

          治---合的過(guò)程

          根據(jù)二叉樹(shù)后序遍歷的特點(diǎn),以本題為例,很明顯根節(jié)點(diǎn)需要遍歷7次,順序如下圖所示:

          合并的規(guī)則如下:

          定義一個(gè)與原數(shù)組長(zhǎng)度相等的臨時(shí)空數(shù)組temp,初始索引t=0,之后每次合并(共7次)左結(jié)點(diǎn)的起始索引為left,末尾索引為mid,右節(jié)點(diǎn)的起始索引為mid+1,末尾索引為right,利用while循環(huán)將左結(jié)點(diǎn)的每一個(gè)值與右結(jié)點(diǎn)的每一個(gè)值做比較,判斷條件為(left <= mid && mid+1 <= right),如果左結(jié)點(diǎn)的值小于右結(jié)點(diǎn)的值,則將左結(jié)點(diǎn)的值賦給temp[t],之后t++,為保證不修改left的值所以將值賦給變量i,i++;相反如果右節(jié)點(diǎn)的值小于左結(jié)點(diǎn)的值,右結(jié)點(diǎn)的值賦給temp[t],之后t++,為保證不修改mid+1的值所以將值賦給變量j,j++;這步做完后,發(fā)現(xiàn)左右個(gè)結(jié)點(diǎn)一定會(huì)有值剩下,因?yàn)樽笥医Y(jié)點(diǎn)的值總會(huì)有一個(gè)先到達(dá)判斷條件,++之后就終止了while循環(huán),因此會(huì)剩余,這時(shí)又會(huì)出現(xiàn)兩種情況,一是左邊剩余(可能不止一個(gè)),另一個(gè)是右邊剩余(可能不止一個(gè)),因此還需要while循環(huán),如果左邊剩余說(shuō)明還沒(méi)到達(dá)mid(結(jié)尾索引),判斷條件為(i <= mid),剩余元素一定是有序的并且是較大值,因此只需添加到臨時(shí)數(shù)組temp的末尾即可,右結(jié)點(diǎn)有值剩余只不過(guò)判斷條件變?yōu)椋╦ <= right),方法一樣。

          最后每次合并都將temp的值copy到傳入的數(shù)組中去即可!

           public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
                  int i = left;//左邊有序序列的初始索引
                  int j = mid + 1;//右邊有序序列的初始索引
                  int t = 0//指向temp數(shù)組的當(dāng)前索引

                  //一
                  //先把左右兩邊有序的數(shù)據(jù)按照規(guī)則填充到temp數(shù)組
                  //直到左右兩邊的有序序列,有一邊處理完畢為止
                  while (i <= mid && j <= right) { //繼續(xù)
                      //如果左邊的有序序列的當(dāng)前元素小于等于右邊有序序列的當(dāng)前元素
                      //即將左邊的當(dāng)前元素填充到temp數(shù)組
                      //然后t++,i++
                      if (arr[i] <= arr[j]) {
                          temp[t] = arr[i];
                          t += 1;
                          i += 1;
                      } else { //反之,則將右邊的有序序列當(dāng)前元素填充到temp數(shù)組
                          temp[t] = arr[j];
                          t += 1;
                          j += 1;
                      }
                  }
                  while (i <= mid) {//將左邊剩余元素全部填充進(jìn)temp中
                      temp[t] = arr[i];
                      t += 1;
                      i += 1;
                  }
                  while (j <= right) {//將右序列剩余元素全部填充進(jìn)temp中
                      temp[t] = arr[j];
                      t += 1;
                      j += 1;
                  }

                  //三
                  //將temp數(shù)組的元素拷貝到arr
                  //注意,并不是每次都拷貝所有
                  t = 0;
                  int tempLeft = left;
                  //第一次合并tempLeft=0,right=1  tempLeft=2,right=3  tempLeft=0,right=3
                  //最后一次tempLeft=0,right=1
                  while (tempLeft <= right) {
                      arr[tempLeft] = temp[t];
                      t += 1;
                      tempLeft += 1;
                  }
              }

          「由于合并次數(shù)過(guò)多,下圖僅將最后一次合并圖解在下圖」

          「第七次合并動(dòng)圖圖解:」

          第七次合并是最后一次合并,可以看到數(shù)組已經(jīng)有序了,最后將temp數(shù)組copy到原數(shù)組即可排序完成!

          時(shí)間復(fù)雜度:O(nlogn)

          空間復(fù)雜度:O(n+logn)

          由于歸并排序在歸并過(guò)程中需要與原始記錄序列同樣數(shù)量的存儲(chǔ)空間存放歸并結(jié)果以及遞歸深度為log2n的??臻g,因此空間復(fù)雜度為O(n+logn),會(huì)造成空間的浪費(fèi),因此可采用迭代繼續(xù)優(yōu)化,但是思路比較復(fù)雜,在本篇文章不做講解!


          瀏覽 63
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  屄屄在线看 | 丁香五月婷婷在线 | 国产亚洲 久一区二区写真 | 色婷婷国产AV | 亚洲V V |