1. 程式人生 > >歸併排序(含樹的前序遍歷,中序遍歷,後續遍歷)

歸併排序(含樹的前序遍歷,中序遍歷,後續遍歷)

       歸併排序是一種分而治之的思想,利用的是遞迴的方法,在實現上與樹的遍歷十分相似。

       所以我打算,先總結一下樹的三種遍歷,並於歸併排序做對比,加深印象。

     前序遍歷

        (1)若二叉樹為空,則為空操作,返回空。         (2)訪問根結點。         (3)前序遍歷左子樹。         (4)前序遍歷右子樹。

   void PreOrderTraverse(BiTree BT)
   {
     if(BT)
     {
        printf("%c",BT->data);              //訪問根結點
        PreOrderTraverse(BT->lchild);       //前序遍歷左子樹
        PreOrderTraverse(BT->rchild);       //前序遍歷右子樹
     }
   }

     中序遍歷

      (1)若二叉樹為空,則為空操作,返回空。       (2)中序遍歷左子樹。       (3)訪問根結點。       (4)中序遍歷右子樹。

    void InOrderTraverse(BiTree BT)
    {
      if(BT)
      {
         InOrderTraverse(BT->lchild);        //中序遍歷左子樹
         printf("%c",BT->data);              //訪問根結點
         InOrderTraverse(BT->rchild);        //中序遍歷右子樹
      }
    }

   後序遍歷

      (1)若二叉樹為空,則為空操作,返回空。       (2)後序遍歷左子樹。       (3)後序遍歷右子樹。       (4)訪問根結點。

     void PostOrderTraverse(BiTree BT)
     {
       if(BT)
       {
          PostOrderTraverse(BT->lchild);        //後序遍歷左子樹
          PostOrderTraverse(BT->rchild);        //後序遍歷右子樹
          printf("%c",BT->data);                //訪問根結點
       }
     }

這裡我覺的非常有必要對遞迴,做一下總結,記得當初初次接觸遞迴的時候,覺得非常難以接受,其實,找一個遞迴深度淺一點的,自己動手,一步一步按照遞迴的思路,畫出過程,就理解了

  1.要解決的問題,可以分成n個相同結構的步驟解決(結構相同,資料不同,下一步的資料,需要上一步的結果)

  2.自己呼叫自己,要想獲取上一步的結果,就必須把自己的結果傳給下一步

  3.遞迴是一個迴圈,所以要給出入口,就是第一步的結果,還要有出口,不然就是死迴圈

然後先上歸併排序的程式碼

package com.example.eurekaribbonclient.test;

import java.util.Arrays;

/**
 * @ClassName test_2
 * @Description TODO
 * @Author Mr.G
 * @Date 2018/9/18 10:32
 * @Version 1.0
 */

public class test_2 {
   public static void main(String [] args){
       int[] arry={9,8,7,6,5,4,3,2,1};
       int[] temp=new int[arry.length];//避免大量開闢空間
       sort(arry,0,arry.length-1,temp);//入口
       System.out.println(Arrays.toString(temp));
   }
   public static void sort(int[] arry,int left,int right,int[] temp){
       if(left<right){//條件不滿足為出口
           int mid=(left+right)/2;
           sort(arry,left,mid,temp);//使左邊有序
           sort(arry,mid+1,right,temp);//使右邊有序
           combin(arry,left,mid,right,temp);//有序合併左右
       }
   }
   public static void combin(int[] arry,int left,int mid,int right,int[] temp){
       int i=left;
       int j=mid+1;
       int t=0;
       while(i<=mid&&j<=right){
           if(arry[i]<=arry[j]){
               temp[t++]=arry[i++];
           }else{
               temp[t++]=arry[j++];
           }
       }
       while(i<=mid){//如果左邊有剩餘,放到數組裡
           temp[t++]=arry[i++];
       }
       while(j<=right){//如果右邊有剩餘,放到數組裡
           temp[t++]=arry[j++];
       }
       t=0;
       while(left<=right){
           arry[left++]=temp[t++];//把資料放回arry[],因為temp會在遞迴過程被不斷使用
       }
   }
}

如果理解還是困難,我們寫個小例子一步一步進去看看。

例如 3 2 4 1

第一步會進入 左邊排序

3  2

讓後繼續左邊排序

3

然後右邊排序

2

合併排序

2 3

a[0]=2 a[1]=3

返回到第一步右邊排序

4 1

左邊排序

4

右邊排序

1

合併

1 4

a[2]=1 a[3]=4

返回到第一步,合併

1 2 3 4

此時 arry和temp的值都是1 2 3 4

遞迴其實就是壓棧和出棧操作,沒呼叫自己一次,就把原來的函式壓棧,找到出口就出棧一個,直到棧空,結果也就出來了

所以符合後進先出