二叉树遍历的各种方式

/*======================================
树的所有操作
初始化二叉树, 先序,中序,后序建立二叉树
先序,中序,后序递归, 非递归 遍历二叉树
层次遍历二叉树等
2013-08-12 By Mei
=======================================*/

#include <iostream>
#include <cstdlib>
#include <queue>
#include <stack>
#define N 20;

using namespace std;

typedef struct Binode // 树的数据结构
{
    int data;
    struct Binode *lchild, *rchild;
}Binode, *Bitree;

typedef struct s_stack
{
    Bitree *top;
    Bitree *base;
    int size;
}s_stack;

typedef struct qnode
{
    Bitree *rear;
    Bitree *front;
}qnode;


int a[] = {1, 2, 3, 0, 0, 4, 5, 0, 6, 0, 0, 7, 0, 0, 0};
// Bitree Create_Tree(Bitree &T)//必须用二级指针 
// {
//     int x;
//     cin>>x;
//     if(x==0)// 输入二叉树的节点,左右节点不存在必须以0 代替,否则递归不能结束
//         T = NULL;
//     else
//     {
//         T = new Binode;
//         T->data = x;
//         cout<<T->data<<endl;
//         Create_Tree(T->lchild);
//         Create_Tree(T->rchild);
//     }
//     return T;
// }
Bitree Create_Tree()
{
    Bitree p;
    static int num = 0;
    if (num <= 20)
    {
        if(a[num]==0)
        {    
            p = NULL;
            num++;
        }

        else
        {
            p=new Binode;
            p->data = a[num];
            p->lchild = p->rchild = NULL;
            cout <<p->data<<" ";
            num++;
            p->lchild = Create_Tree();
            p->rchild = Create_Tree();// 尼玛 指针被这里覆盖了..
        }
    }
    else //递归出来的时候需注意..
       p = NULL; 
    return p;
}

//先序递归遍历
void Rec_PreorderTraverse(Bitree root) 
{
    if(root != NULL)
    {
        cout<<root->data<<" ";
        Rec_PreorderTraverse(root->lchild);
        Rec_PreorderTraverse(root->rchild);
    }
}

// 先序非递归遍历
/*
思想:利用栈实现,首先根节点进站,然后右节点进栈,接着左节点进栈
然后弹出栈顶节点,判断栈顶节点的右节点是否存在,存在则压入栈,继续判断
其左节点是否存在,存在则压入栈中,然后继续弹出栈顶元素,反复循环,知道栈为
空为止
*/
void PreorderTraverse(Bitree root) 
{
    s_stack st;
    Bitree p = root;
    st.base = new Bitree[20];
    st.size = N;
    st.top = st.base;
    *st.top++ = p;
    while(st.top!=st.base)
    {
        p=*--st.top;
        cout<<p->data<<" ";
        if(p->rchild!=NULL)
        {
            *st.top++ = p->rchild;
        }
        if(p->lchild!=NULL)
        {
            *st.top++ = p->lchild;
        }
    }

}
//中序递归遍历
void Rec_InorderTraverse(Bitree root) 
{
    if(root != NULL)
    {
        Rec_InorderTraverse(root->lchild);
        cout<<root->data<<" ";
        Rec_InorderTraverse(root->rchild);
    }
}

//中序非递归遍历
/*
思想:首先压入根节点,如果其左节点存在,继续压入其左节点,知道左节点为空
然后弹出栈顶元素,判断其右节点是否存在,若存在压入栈中,继续判断其左节点是否存在
若存在,继续压入其左节点,知道其左节点不存在为止,然后反复循环,知道栈为空为止
*/
void InorderTraverse(Bitree root) 
{
    s_stack st;
    Bitree p = root;
    Bitree x, y;
    st.base = new Bitree[20];
    st.size = N;
    st.top = st.base;
    while(p!=NULL)
    {
        *st.top++ = p;
        p = p->lchild;
    }
    while(st.top!=st.base)
    {
        x = *--st.top;
        cout<<x->data<<" ";
        if(x->rchild!=NULL)
        {
            *st.top++ = x->rchild;
            y = x->rchild;
            while(y->lchild!=NULL)
            {
                *st.top++ = y->lchild;
                y = y->lchild;
            }
        }
    }
}

void Rec_PostorderTraverse(Bitree root) //后序递归遍历
{
    if(root != NULL)
    {
        Rec_PostorderTraverse(root->lchild);
        Rec_PostorderTraverse(root->rchild);
        cout<<root->data<<" ";
    }
}

//后序非递归遍历
/*
先压入根节点到栈中,如果其左节点非空,一直压入左节点,知道左节点为空为止,此时取出栈顶元素
只是去取,并非弹栈,然后标记这个节点,表示这个节点的右子节点已经被访问过,下次遇到这个节点
直接弹出即可
(1)判断这个节点是否有右子节点 或者右子节点是否被访问过,如果是,则弹出这个节点
(2)如果这个节点的右子节点没有被访问过,则右子节点压入栈中,重复刚开始的其是否存在左子节点的判断
*/
void PostorderTraverse(Bitree root)
{
    s_stack st;
    Bitree p = root;
    st.base = new Bitree[20];
    st.top = st.base;
    Bitree x,y;
    int flag[10];//标记是否访问过这个节点
    while(p!=NULL)
    {
        *st.top++ = p;
        p = p->lchild;
        flag[st.top-st.base-1] = 0;
        
    }
    while(st.top!=st.base)
    {
        p = *(st.top-1);
        if(flag[st.top-st.base-1]==0)
        {
            flag[st.top-st.base-1] = 1;
            if(p->rchild!=NULL)
            {
                x = p->rchild;
                while(x!=NULL)
                {
                    *st.top++ = x;
                    x = x->lchild;  
                    flag[st.top-st.base-1] = 0; 
                }
            }
        }
        else
        {
            x = *--st.top;
            cout<<x->data<<" ";
        }
    }
}

//层次遍历
void TraversalOfLevel(Bitree root)
{
    qnode st;
    Bitree p;
    st.front = new Bitree[20];
    st.rear = st.front;
    *st.front++ = root;
    while(st.front!=st.rear)
    {
        p = *st.rear++;
        cout<<p->data<<" ";
        if(p->lchild!=NULL)
            *st.front++ = p->lchild;
        if(p->rchild!=NULL)
            *st.front++ = p->rchild;
    }
}


//先序,中序,后序 非递归遍历的第二种思路
//先序非递归遍历的第二种方法
/*
对任一节点来说
(1)访问节点p,节点入栈
(2)判断其左孩子是否为空,如果为空,进行出栈操作,并将栈顶元素的右孩子设置为p,
    循环到1,若不为空,则将节点p的左孩子设置为当前的节点P
(3)若P为NULL 且栈为空,则结束遍历

*/

void PreorderTraverse1(Bitree root)
{
    stack<Bitree> s;
    Bitree p = root;
    while(p!=NULL||!s.empty())
    {
        while(p!=NULL)
        {
            cout<<p->data<<" ";
            s.push(p);
            p = p->lchild;
        }
        if(!s.empty())
        {   
            p = s.top();
            s.pop();
            p = p->rchild;
        }
    }
}

//中序非递归遍历
/*
对任一节点来说:
(1)若左节点不空,则将p入栈,并将p的左孩子置为P,重复这个操作,直到p的左孩子为空为止
(2)若左孩子为空,则取栈顶元素并出栈,访问栈顶元素,然后将P的右孩子置为P为止
(3)当P为NULL,且栈为空 则遍历完成
*/

void InorderTraverse1(Bitree root)
{
    stack<Bitree> s;
    Bitree p = root;
    while(p!=NULL||!s.empty())
    {
        while(p!=NULL)
        {
            s.push(p);
            p = p->lchild;
        }
        if(!s.empty())
        {
            p = s.top();
            cout<<p->data<<" ";
            s.pop();
            p = p->rchild;
        }
    }

}

// 后序非递归遍历第二种实现方式
/*
对任一节点P,将其入栈,然后沿左子树一起向下搜索,知道左子树为空为止
此时获取栈顶元素,但是此时还不能出栈访问,因为其右孩子还未被访问,此时对
其标记一下,表示右节点已经访问过,然后让右节点入栈,重复前面的操作,知道遇到
已经标记过的节点,此时表明此节点的右节点已经都被访问完成
*/
void PostorderTraverse1(Bitree root)
{
    stack<Bitree> s;
    int flag[20];
    int x;
    Bitree p = root;
    while(p!=NULL||!s.empty())
    {
        while(p!=NULL)
        {
            s.push(p);
            flag[s.size()] = 0;
            p = p->lchild;
        }
        if(!s.empty())
        {
            x = flag[s.size()];
            p = s.top();
            if(x == 0)
            {
                flag[s.size()] = 1;
                p = p->rchild;
            }
            else
            {
                cout<<p->data<<" ";
                s.pop();
                p = NULL;
            }
        }
    }
}

// 后序遍历的第三种形式
/*
要保证先访问左右节点,然后再访问根节点,可以先把根节点入栈,然后其右节点,左节点分别入栈
如果根节点没有左右节点,或者左右节点已经被访问过,根节点就可以出战,这样可以保证每次取栈顶
元素的时候,左节点在右节点前面被访问,根节点在左节点,右节点前面被访问
*/
void PostorderTraverse2(Bitree root)
{
    stack <Bitree> s;
    Bitree cur, pre=NULL;
    s.push(root);
    while(!s.empty())
    {
        cur = s.top();
        if((cur->rchild==NULL && cur->lchild==NULL)||(pre!=NULL &&(pre==cur->lchild||pre==cur->rchild)))
        {
            cout<<cur->data<<" ";
            s.pop();
            pre = cur;
        }
        else
        {
            if(cur->rchild!=NULL)
                s.push(cur->rchild);
            if(cur->lchild!=NULL)
                s.push(cur->lchild);
        }
    }
}

int main()
{
    Bitree T, root;
    root = Create_Tree();
    cout<<endl;
    cout<<"先序遍历结果:"<<endl;
    Rec_PreorderTraverse(root);
    cout<<endl;
    PreorderTraverse(root);
    cout<<endl;
    PreorderTraverse1(root);
    cout<<endl;
    cout <<"中序遍历结果:"<<endl;
    Rec_InorderTraverse(root);
    cout<<endl;
    InorderTraverse1(root);
    cout<<endl;
    InorderTraverse(root);
    cout<<endl;
    cout << "后序遍历结果:"<<endl;
    Rec_PostorderTraverse(root);
    cout<<endl;
    PostorderTraverse(root);
    cout<<endl;
    PostorderTraverse1(root);
    cout <<endl;
    PostorderTraverse2(root);
    cout<<endl;
    cout<<"层次遍历结果:"<<endl;
    TraversalOfLevel(root);
    cout<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值