<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>

          Java實(shí)現(xiàn)-歸并排序算法-動圖詳解

          共 1148字,需瀏覽 3分鐘

           ·

          2021-01-07 23:46

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

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

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

          分的過程

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

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

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

          治---合的過程

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

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

          定義一個與原數(shù)組長度相等的臨時空數(shù)組temp,初始索引t=0,之后每次合并(共7次)左結(jié)點(diǎn)的起始索引為left,末尾索引為mid,右節(jié)點(diǎn)的起始索引為mid+1,末尾索引為right,利用while循環(huán)將左結(jié)點(diǎn)的每一個值與右結(jié)點(diǎn)的每一個值做比較,判斷條件為(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)左右個結(jié)點(diǎn)一定會有值剩下,因?yàn)樽笥医Y(jié)點(diǎn)的值總會有一個先到達(dá)判斷條件,++之后就終止了while循環(huán),因此會剩余,這時又會出現(xiàn)兩種情況,一是左邊剩余(可能不止一個),另一個是右邊剩余(可能不止一個),因此還需要while循環(huán),如果左邊剩余說明還沒到達(dá)mid(結(jié)尾索引),判斷條件為(i <= mid),剩余元素一定是有序的并且是較大值,因此只需添加到臨時數(shù)組temp的末尾即可,右結(jié)點(diǎn)有值剩余只不過判斷條件變?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ù)過多,下圖僅將最后一次合并圖解在下圖」

          「第七次合并動圖圖解:」

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

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

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

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


          瀏覽 58
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  亚洲看片 | 人妻系列无码 | www.伊人大香蕉 | 黄色免费成人视频 | 美女黄页网站 |