1. 程式人生 > >二叉樹後序遍歷的迭代實現

二叉樹後序遍歷的迭代實現

#include <stdio.h>
#include <stdlib.h>
struct BinTreeNode{
    int Element;
    int visited;//用於標記當前節點有沒有被訪問過
    struct BinTreeNode* Left;
    struct BinTreeNode* Right;
};
//以下程式碼用於建樹,便於測試中序遍歷程式是否正確
struct BinTreeNode* CreateNode(int data){//創造新節點
    struct BinTreeNode* temp;
    temp=(struct BinTreeNode*)malloc(sizeof(struct BinTreeNode));
    if(temp!=NULL){
        temp->Element=data;
        temp->visited=0;
        temp->Left=NULL;
        temp->Right=NULL;
    }
    return temp;
}
struct BinTreeNode* FindNode(struct BinTreeNode* BinTree,int data)//查詢
{
    if(BinTree==NULL)
        return NULL;
    if(BinTree->Element==data)
        return BinTree;
    struct BinTreeNode* temp=NULL;
    if(BinTree->Left!=NULL)
        temp=FindNode(BinTree->Left,data);
    if(temp==NULL&&BinTree->Right!=NULL)
        temp=FindNode(BinTree->Right,data);
    return temp;

}
//假設每個節點值不同
#define LEFT 1
#define RIGHT 0
struct BinTreeNode* InsertNode(struct BinTreeNode* BinTree,int loc,int dir,int data)//插入節點,loc代表插入的數的父節點的值,dir表示方向
{
    struct BinTreeNode* parent=FindNode(BinTree,loc);
    if(parent!=NULL){
        struct BinTreeNode* temp=CreateNode(data);
        if(dir==LEFT)
            parent->Left=temp;
        else
            parent->Right=temp;
    }
    return BinTree;
}
//二叉樹前序遍歷的迭代實現,用到棧
/*
思路:
後序不同於前序和中序,後序要訪問完左子樹和右子樹才能訪問節點;
因此遍歷到一個節點,訪不訪問他取決於它的左右子樹是不是均被訪問過了;
需要在結構體中加入一個用來判斷的變數visited,如果其左右子樹均被訪問過,就賦值為1
過程:
當前節點,沿它的左路徑,開始遍歷,直到路徑末尾,開始回溯
回溯過程中的節點的左兒子一定被訪問過了或者不存在,如果其右兒子不存在或者右兒子已經被訪問過,訪問當前節點
如果其右兒子存在,此時以其右兒子為基礎,再去遍歷其左路徑
*/
void PostOrderTrversal(struct BinTreeNode* BinTree)
{
    //建棧
    struct BinTreeNode* stack[100];
    int top=-1;
    int flag;//判斷要不要去遍歷一個新的 (子)樹左路徑
    struct BinTreeNode* Temp=BinTree;
    while(Temp!=NULL||top>=0){
        flag=1;
        while(Temp!=NULL){//遍歷 (子)樹左路徑
            Temp->visited=1;
            top++;
            stack[top]=Temp;
            Temp=Temp->Left;
        }
        while(flag&&top>=0){
           if(stack[top]->Right==NULL||stack[top]->Right->visited==1){//右兒子不存在或者右兒子已經被訪問過
              printf("%d ",stack[top]->Element);
              top--;
           }
           else{
              Temp=stack[top]->Right;
              flag=0;//flag為0,遍歷一個新的 (子)樹左路徑
           }
        }
    }
    return;
}
int main()
{
    struct BinTreeNode* BinTree;
    //先手工建立一個樹  //不提倡此類建樹方法,只是暫時用於測試程式
    BinTree=CreateNode(10);
    BinTree=InsertNode(BinTree,10,1,20);
    BinTree=InsertNode(BinTree,10,0,30);
    BinTree=InsertNode(BinTree,30,1,40);
    BinTree=InsertNode(BinTree,40,0,50);
    //遍歷
    PostOrderTrversal(BinTree);
    return 0;
}
//不用flag也可以
#include <stdio.h>
#include <stdlib.h>
struct BinTreeNode{
    int Element;
    int visited;//用於標記當前節點有沒有被訪問過
    struct BinTreeNode* Left;
    struct BinTreeNode* Right;
};
//以下程式碼用於建樹,便於測試中序遍歷程式是否正確
struct BinTreeNode* CreateNode(int data){//創造新節點
    struct BinTreeNode* temp;
    temp=(struct BinTreeNode*)malloc(sizeof(struct BinTreeNode));
    if(temp!=NULL){
        temp->Element=data;
        temp->visited=0;
        temp->Left=NULL;
        temp->Right=NULL;
    }
    return temp;
}
struct BinTreeNode* FindNode(struct BinTreeNode* BinTree,int data)//查詢
{
    if(BinTree==NULL)
        return NULL;
    if(BinTree->Element==data)
        return BinTree;
    struct BinTreeNode* temp=NULL;
    if(BinTree->Left!=NULL)
        temp=FindNode(BinTree->Left,data);
    if(temp==NULL&&BinTree->Right!=NULL)
        temp=FindNode(BinTree->Right,data);
    return temp;

}
//假設每個節點值不同
#define LEFT 1
#define RIGHT 0
struct BinTreeNode* InsertNode(struct BinTreeNode* BinTree,int loc,int dir,int data)//插入節點,loc代表插入的數的父節點的值,dir表示方向
{
    struct BinTreeNode* parent=FindNode(BinTree,loc);
    if(parent!=NULL){
        struct BinTreeNode* temp=CreateNode(data);
        if(dir==LEFT)
            parent->Left=temp;
        else
            parent->Right=temp;
    }
    return BinTree;
}
//二叉樹前序遍歷的迭代實現,用到棧
/*
思路:
後序不同於前序和中序,後序要訪問完左子樹和右子樹才能訪問節點;
因此遍歷到一個節點,訪不訪問他取決於它的左右子樹是不是均被訪問過了;
需要在結構體中加入一個用來判斷的變數visited,如果其左右子樹均被訪問過,就賦值為1
過程:
當前節點,沿它的左路徑,開始遍歷,直到路徑末尾,開始回溯
回溯過程中的節點的左兒子一定被訪問過了或者不存在,如果其右兒子不存在或者右兒子已經被訪問過,訪問當前節點
如果其右兒子存在,此時以其右兒子為基礎,再去遍歷其左路徑
*/
void PostOrderTrversal(struct BinTreeNode* BinTree)
{
    //建棧
    struct BinTreeNode* stack[100];
    int top=-1;
    struct BinTreeNode* Temp=BinTree;
    while(Temp!=NULL||top>=0){
        while(Temp!=NULL){//遍歷 (子)樹左路徑
            Temp->visited=1;
            top++;
            stack[top]=Temp;
            Temp=Temp->Left;
        }
        if(top>=0){
           if(stack[top]->Right==NULL||stack[top]->Right->visited==1){//右兒子不存在或者右兒子已經被訪問過
              printf("%d ",stack[top]->Element);
              top--;
           }
           else
              Temp=stack[top]->Right;
        }
    }
    return;
}
int main()
{
    struct BinTreeNode* BinTree;
    //先手工建立一個樹  //不提倡此類建樹方法,只是暫時用於測試程式
    BinTree=CreateNode(10);
    BinTree=InsertNode(BinTree,10,1,20);
    BinTree=InsertNode(BinTree,10,0,30);
    BinTree=InsertNode(BinTree,30,1,40);
    BinTree=InsertNode(BinTree,40,0,50);
    //遍歷
    PostOrderTrversal(BinTree);
    return 0;
}