二叉樹遍歷(遞歸+非遞歸)


二叉樹的遞歸很簡單,但是非遞歸就有點復雜了。

第一種先序遍歷、中序遍歷、第一種后序遍歷都是一直將左子樹壓入棧,其中先序遍歷和中序遍歷輸出位置不同,后序遍歷則需要前驅標記pre來判斷右孩子是否訪問過;

第二種先序遍歷和第二種后序遍歷是根據層序遍歷的思想寫的,將隊列換成棧,順序換成先入右孩子再入左孩子,但是后序遍歷需要用pre判斷左右孩子是否都訪問過。

測試數據:AB#DF##G##CEH##I###

 

#include <bits/stdc++.h>
using namespace std;
struct node
{
    char data;
    node *l, *r;
};

//建立二叉樹
void creat(node *&t)
{
    char c;
    cin>>c;
    if(c == '#')
    {
        t = NULL;
        return;
    }
    t = (node*)malloc(sizeof(node));
    t->data = c;
    creat(t->l);
    creat(t->r);
}

//先序遍歷二叉樹(遞歸)
void pre_di(node *t)
{
    if(!t) return;
    printf("%c ", t->data);
    pre_di(t->l);
    pre_di(t->r);
}

//中序遍歷二叉樹(遞歸)
void in_di(node *t)
{
    if(!t) return;
    in_di(t->l);
    printf("%c ", t->data);
    in_di(t->r);
}

//后序遍歷二叉樹(遞歸)
void post_di(node *t)
{
    if(!t) return;
    post_di(t->l);
    post_di(t->r);
    printf("%c ", t->data);
}

//先序遍歷二叉樹(非遞歸1)
void pre_no_di1(node *t)
{
    stack<node*>S;
    while(t || !S.empty())
    {
        if(t)
        {
            printf("%c ", t->data);
            S.push(t);
            t = t->l;
        }
        else
        {
            t= S.top();
            S.pop();
            t = t->r;
        }
    }
    cout<<endl;
}

//先序遍歷二叉樹(非遞歸2)
void pre_no_di2(node *t)
{
    stack<node*>S;
    S.push(t);
    while(!S.empty())
    {
        t = S.top();
        S.pop();
        printf("%c ", t->data);
        if(t->r) S.push(t->r);
        if(t->l) S.push(t->l);
    }
    cout<<endl;
}

//中序遍歷二叉樹(非遞歸)
void in_no_di(node *t)
{
    stack<node*>S;
    while(t || !S.empty())
    {
        if(t)
        {
            S.push(t);
            t = t->l;
        }
        else
        {
            t = S.top();
            S.pop();
            printf("%c ", t->data);
            t = t->r;
        }
    }
    cout<<endl;
}

//后序遍歷二叉樹(非遞歸1)
void post_no_di1(node *t)
{
    stack<node*>S;
    node *pre = NULL;
    while(t || !S.empty())
    {
        while(t)
        {
            S.push(t);
            t = t->l;
        }
        t = S.top();
        if(!t->r || pre == t->r)
        {
            printf("%c ", t->data);
            pre = t;
            S.pop();
            t = NULL;
        }
        else
            t = t->r;
    }
    cout<<endl;
}

//后序遍歷二叉樹(非遞歸2)
void post_no_di2(node *t)
{
    stack<node*>S;
    node *pre = NULL;//pre本來想寫char類型,但是下面if里就要換成pre==t->l->data,如果t->l為空則會報錯!
    S.push(t);
    while(!S.empty())
    {
        t = S.top();
        if((t->l == NULL && t->r == NULL) || (pre != NULL && (pre == t->l || pre == t->r))) //pre=t->l代表僅有左且已訪問或者先訪問過右又訪問了左
        {
            printf("%c ", t->data);
            pre = t;
            S.pop();
        }
        else
        {
            if(t->r) S.push(t->r);
            if(t->l) S.push(t->l);
        }
    }
    cout<<endl;
}

//層序遍歷
void ceng(node *t)
{
    queue<node*>Q;
    Q.push(t);
    while(!Q.empty())
    {
        t = Q.front();
        Q.pop();
        printf("%c ", t->data);
        if(t->l) Q.push(t->l);
        if(t->r) Q.push(t->r);
    }
    cout<<endl;
}

//銷毀二叉樹
void Free(node *&t)
{
    if(t->l) Free(t->l);
    if(t->r) Free(t->r);
    free(t);
}

int main()
{
    node *t;
    puts("請輸入二叉樹");
    creat(t);
    puts("創建成功");
    printf("先序遍歷二叉樹(遞歸):   ");
    pre_di(t);
    cout<<endl;
    printf("先序遍歷二叉樹(非遞歸1):");
    pre_no_di1(t);
    printf("先序遍歷二叉樹(非遞歸2):");
    pre_no_di2(t);
    printf("\n中序遍歷二叉樹(遞歸):   ");
    in_di(t);
    cout<<endl;
    printf("中序遍歷二叉樹(非遞歸): ");
    in_no_di(t);
    printf("\n后序遍歷二叉樹(遞歸):   ");
    post_di(t);
    cout<<endl;
    printf("后序遍歷二叉樹(非遞歸1):");
    post_no_di1(t);
    printf("后序遍歷二叉樹(非遞歸2):");
    post_no_di2(t);
    printf("\n層序遍歷二叉樹:");
    ceng(t);
    Free(t);
    return 0;
}

 

運行截圖:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM