歸併排序(含樹的前序遍歷,中序遍歷,後續遍歷)
歸併排序是一種分而治之的思想,利用的是遞迴的方法,在實現上與樹的遍歷十分相似。
所以我打算,先總結一下樹的三種遍歷,並於歸併排序做對比,加深印象。
前序遍歷
(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
遞迴其實就是壓棧和出棧操作,沒呼叫自己一次,就把原來的函式壓棧,找到出口就出棧一個,直到棧空,結果也就出來了
所以符合後進先出