二叉树遍历的各种方式

来源:互联网 发布:linux系统配置ip地址 编辑:程序博客网 时间:2024/05/20 15:59
/*======================================树的所有操作初始化二叉树, 先序,中序,后序建立二叉树先序,中序,后序递归, 非递归 遍历二叉树层次遍历二叉树等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;}