• 二叉树的三种非递归遍历和层次遍历


    1 .三种非递归遍历(栈)

    所要遍历的树是:

    这里写图片描述

    先序 + 中序

    思路:就拿先序遍历为例来说吧。

        1.访问根节点,根节点入栈,进入左子树。
        2.访问左子树的根节点,根节点入栈,进入下一层左子树。
        3.重复直到当前节点为空。即到达了最**左下方**的节点
        4.如果栈不为空,就从栈顶取出节点,进入其右子树
        5.直到当前节点和栈都为空时,结束。(栈为空就是所有的入栈的节点的右子树都访问过了。当前节点为空就代表所有的节点都访问过了)
    

    实现代码:

    #include<iostream>
    using namespace std;
    
    typedef struct Node {
        char data ;
        struct Node * Lchild ;
        struct Node * Rchild ;
    }BiNode ,*BiTree ;
    
    typedef struct temp{
        BiTree ptr;
        struct temp *next ;
    }SeqStack;
    
    void CreteBitree(BiTree *root)  
    {
        char ch ;
        cin >> ch ;
        if( ch == '#' ) 
            *root= NULL;
        else {
            *root = (BiTree)malloc(sizeof(BiNode));
            (*root)->data = ch;
            CreteBitree(&(*root)->Lchild);
            CreteBitree(&(*root)->Rchild);
        }
    }
    void InitSeqStack(SeqStack **S)     // 用链表来实现一个栈
    {
        *S = (SeqStack *)malloc(sizeof(SeqStack));
        (*S)->next = NULL ;
    }
    void Push(SeqStack *S,BiTree p)
    {
        SeqStack *temp ;
        temp = (SeqStack *)malloc(sizeof(SeqStack));
        temp-> ptr = p;
        temp->next = S->next ;
        S->next = temp ;
    }
    
    void Pop(SeqStack *S ,BiTree *p)
    {
        SeqStack *t ;
        t= S->next ;
        *p = t->ptr ;
        S->next = t->next ;
        free(t);
    }
    int IsEmpty(SeqStack *S)
    {
        if(S->next == NULL )
            return 1;
        else return 0;
    }
    void InOrder(BiTree root) //中序
    {
        SeqStack *S;
        BiTree p ;
        InitSeqStack(&S); 
        p = root ;
        while(p != NULL || !IsEmpty(S) )
        {
            while(p != NULL )
            {
                //入栈
                Push(S,p);
                p=p->Lchild;
            }
            if(!IsEmpty(S))
            {
                Pop(S,&p);
                cout << p->data ;
                p=p->Rchild ;
            }
        }
        cout << endl ;
    }
    void PreOrder(BiTree root) //先序
    {
        SeqStack *S;
        BiTree p ;
        InitSeqStack(&S); 
        p = root ;
        while(p != NULL || !IsEmpty(S) )
        {
            while(p != NULL )
            {
                //入栈
                cout << p->data ;
                Push(S,p);
                p=p->Lchild;
            }
            if(!IsEmpty(S))
            {
                Pop(S,&p);
                p=p->Rchild ;
            }
        }
        cout << endl ;
    }
    
    int main(void)
    {
        BiTree root;
        cout  << "Please input the  string :" << endl ;
    
        CreteBitree(&root);
        cout << "非递归!!!先序:" << endl ;
        PreOrder(root); 
        cout << endl;
    
        cout << "非递归!!!中序:" << endl ;
        InOrder(root); 
        cout << endl;
        return 0;
    }

    运行截图:

    这里写图片描述

    后序

    思路:后序的遍历要比前面的两种复杂一些。因为在前面我们的思路就是进左子树,然后从左子树返回,退栈,进右子树。而在后序中,我们是必须先访问完左右子树才能退栈,访问根节点。那么我们如何知道是从哪个子树返回的呐?其实也很简单的啦。就设置一个标记(tag),左为0,右为1。如果tag==1就退栈返回,如果不为1,就修改它的tag==1,继续压回去,往右子树走就行了

    实现代码:

    #include<iostream>
    using namespace std;
    
    typedef struct Node {
        char data ;
        struct Node * Lchild ;
        struct Node * Rchild ;
    }BiNode ; 
    
    typedef struct temp{
        BiNode *ptr;
        int tag ;
        struct temp *next ;
    }SeqStack;
    
    void CreteBitree(BiNode **root)  
    {
        char ch ;
        cin >> ch ;
        if( ch == '#' ) 
            *root= NULL;
        else {
            *root = (BiNode *)malloc(sizeof(BiNode));
            (*root)->data = ch;
            CreteBitree(&(*root)->Lchild);
            CreteBitree(&(*root)->Rchild);
        }
    }
    
    void InitSeqStack(SeqStack **S)  //开始创建链表 ,S 就是头节点
    {
        *S = (SeqStack *)malloc(sizeof(SeqStack));
        (*S)->next = NULL ;
    }
    
    void Push(SeqStack *S,SeqStack p)
    {
        SeqStack *temp ;
        temp=(SeqStack *)malloc(sizeof(SeqStack));
        temp->tag = p.tag ;
        temp->ptr = p.ptr ;
        temp->next = S->next ;
        S->next = temp ;
    }
    
    SeqStack Pop(SeqStack *S ,SeqStack p)
    {
        SeqStack *t ;
        t= S->next ;
        p.ptr = t->ptr ;
        p.tag = t->tag ;
        S->next = t->next ;
        free(t);
        return p ;
    }
    int IsEmpty(SeqStack *S)
    {
        if(S->next == NULL )
            return 1;
        else return 0;
    }
    void PostOrder_with_stack(BiNode *root)
    {
        SeqStack *S;
        SeqStack p ;
        InitSeqStack(&S); 
        p.ptr = root ;
        while(p.ptr != NULL || !IsEmpty(S) )
        {
            while(p.ptr != NULL )
            {
                //入栈
                p.tag= 0 ;
                Push(S,p);
                p.ptr=p.ptr->Lchild;
            }
            if(!IsEmpty(S))
            {
                p=Pop(S,p);
        //cout << "3333333" << endl ;
                if(p.tag == 0 ){
                    p.tag = 1;
                    Push(S,p);
                    p.ptr=p.ptr->Rchild;
                }
                else{
                    cout << p.ptr->data ;
                    p.ptr = NULL  ; // 思考一下这是为什么??
                }
            }
        }
        cout << endl ;
    }
    
    int main(void)
    {
        BiNode *root;
        cout  << "Please input the  string :" << endl ;
    
        CreteBitree(&root);
        cout << "非递归!!!后序遍历:" << endl;
        PostOrder_with_stack(root);  
        return 0;
    }

    运行截图:

    这里写图片描述

    总结:三种不同的遍历过程的搜索路径是相同的,不同的仅是三次经过节点时哪一次访问节点。但无论那次经过节点访问时,在第一次经过节点时,都需要保留其节点信息。以便返回时,找到其右子树或者该节点。

    2.层次遍历(队列+BFS)

    思路:先访问的节点的其孩子也将先访问,后访问的节点的其孩子也将后访问,先进先出与队列的形式相同哦

        1.队头节点出队,并访问出队节点
        2.出队节点的左右孩子依次入队
    

    实现代码:

    #include<iostream>
    using namespace std;
    
    typedef struct Node {
        char data ;
        struct Node * Lchild ;
        struct Node * Rchild ;
    }BiNode ; 
    typedef struct t1{
        BiNode *ptr ;
        struct t1 *next ;
    }Queue;
    typedef struct t2{  
        Queue *front;
        Queue *rear;
    }LinkList_Queue;
    void CreteBitree(BiNode **root)  
    {
        char ch ;
        cin >> ch ;
        if( ch == '#' ) 
            *root= NULL;
        else {
            *root = (BiNode *)malloc(sizeof(BiNode));
            (*root)->data = ch;
            CreteBitree(&(*root)->Lchild);
            CreteBitree(&(*root)->Rchild);
        }
    }
    void InitQueue(LinkList_Queue **Q)
    {
        *Q =(LinkList_Queue *)malloc(sizeof(LinkList_Queue)) ;
        (*Q)->front = (*Q)->rear = (Queue *)malloc(sizeof(Queue));
        (*Q)->front->next  = NULL;
    }
    
    void InQueue(LinkList_Queue *Q ,BiNode *p)
    {
        Queue *temp ;
        temp = (Queue *)malloc(sizeof(Queue));
        temp->ptr = p ;
        temp->next = Q->rear->next ;  //尾插
        Q->rear->next = temp ;
        Q->rear = temp ;
    }
    void OutQueue(LinkList_Queue *Q,BiNode **p)  //赋值给p ,头取
    {
        Queue *temp ;
        temp = Q->front->next;
        (*p) = Q->front->next->ptr ;
        Q->front->next = temp->next ;
        if(Q->front->next == NULL ) //一个元素时,需要修改尾指针 !!!!
            Q->front = Q->rear ;
    }
    
    int IsEmpyt(LinkList_Queue *Q)
    {
        if(Q->front == Q->rear )  
            return 1;
        else return 0;
    }
    void LevelOrder(BiNode *root) //层次遍历
    {
        LinkList_Queue *Q;
        BiNode *p;
        InitQueue(&Q);
        InQueue(Q,root);
        while( !IsEmpyt(Q))
        {
            OutQueue(Q,&p);  //p 是 BiNode 型的,Q 是LinkList_Queue 型的
            cout << p->data << "  ";
            if(p->Lchild != NULL )
                InQueue(Q,p->Lchild);
            if(p->Rchild != NULL)
                InQueue(Q,p->Rchild);
        }
        cout << endl ;
    }
    int main(void)
    {
        BiNode *root;
        cout  << "Please input the  string :" << endl ;
        CreteBitree(&root);
        cout << "层次遍历:" << endl ;
        LevelOrder(root);
        cout << endl;
        return 0;
    }
    

    运行截图:

    这里写图片描述

    PS:如果不懂的童鞋,就看下面的参考学习中的视频(是我找到的很好的视频哦),看完就会了,耶!

    参考学习:参考学习

  • 相关阅读:
    利用JSGrid创建甘特图
    Using the SharePoint 2010 Client Object Model_part_2
    Using the SharePoint 2010 Client Object Model_part_1
    如何利用Featue对特定的文档库或列表添加listviewtoolbar上的button
    SharePoint 2010 工作流解决方案:创建带有关联窗体和启动窗体的工作流
    Wireshark过滤器
    first blog
    DataAdapter.update如果处理自动增长列的数据
    ms sql 中关于spid=2的问题
    利用ADO.NET RowUpdating更新DataRow信息
  • 原文地址:https://www.cnblogs.com/Tattoo-Welkin/p/10335318.html
Copyright © 2020-2023  润新知