zoukankan      html  css  js  c++  java
  • 二叉树的几种遍历以及给两种求另外一种

    1.  二叉树 定义结点类型

    typedef struct node
    {
        int data;
        struct node* lchild;
        struct node* rchild;
    } Tnode;

    2.  二叉树的先序遍历:根节点——左子树——右字树

       递归遍历:

    void PreOrder(Tnode*  root)
    {
        if(root==NULL)
            return ;
        cout<<root->val<<endl;
        Preorder(root->lchild);
        Preorder(root->rchild);
    }

       非递归遍历:先序遍历时,每当我们压入一个结点,我们压入结点前对其进行访问

    void PreOrder(Tnode *root)
    {
        if(root==NULL)
            return ;
        stack<Tnode *>s;
        Tnode *now=root;
        while(!s.empty() || now)
        {
            while(now)
            {
                cout<<now->val<<"->";
                s.push(now);
                now=now->lchild;
            }
            now=s.top();
            s.pop();
            now=now->rchild;  
        }
        cout<<endl;
    }

    3.  二叉树的中序遍历:左子树——根节点——右字树

       递归遍历:

    void InOrder(Tnode*  root)
    {
        if(root==NULL)
            return ;
        Preorder(root->lchild);
        cout<<root->val<<endl;
        Preorder(root->rchild);
    }

       非递归遍历:中序时我们需要在遍历完左子树后访问根节点,再去遍历右子树

    void InOrder(Tnode *root)
    {
        if(root==NULL)
            return ;
        stack<Tnode *>s;
        Tnode *now=root;
        while(!s.empty() || now)
        {
            while(now)
            {
                s.push(now);
                now=now->lchild;
            }
            now=s.top();
            cout<<now->val<<"->";
            s.pop();
            now=now->rchild;  
        }
        cout<<endl;
    }

    4.  后序遍历:左子树——右字树——根节点

       递归遍历:

    void PostOrder(Tnode*  root)
    {
        if(root==NULL)
            return ;
        Preorder(root->lchild);
        Preorder(root->rchild);
        cout<<root->val<<endl;
    }

       非递归遍历:后序遍历时由于访问完左右子树后才能访问根结点,因此需要将根结点在栈内保留到左右子树被访问后,但同时会出现一个问题,当右子树弹出后遇到根结点又会将右子树结点压入栈中,造成死循环,因此我们需要在定义一个变量last代表最后一个访问的结点,当last与栈顶结点的右子树结点相同时,则不再将右子树结点压入栈中。

    void PostOrder(Tnode *root)
    {
        if(root==NULL)
            return ;
        stack<Tnode *>s;
        Tnode *now=root;
        Tnode *last=NULL;
        while(!s.empty() || now)
        {
            while(now)
            {
                s.push(now);
                now=now->lchild;
            }
            now=s.top();
            if(now->rchild && last!=now->rchild)
                now=now->rchild;
            else if(now->rchild ==NULL || last ==now->rchild)
            {
                cout<<<now->val<<"->";
                last=now;
                s.pop();
                now=NULL;
            }
        }
    }

    5.   给定中序和前序,求层序(后序都是一样的,主要是建树的过程)。

       首先我们在上面介绍了前序,中序,后序遍历的特性。所以我们基本的思路就是先找到当前树的根节点,然后划分为左子树,右子树,然后进入左子树重复上面的过程,然后进入右子树重复上面的过程。最后就可以还原一棵树了。给个例子介绍一下:

       前序遍历:         GDAFEMHZ

       中序遍历:         ADEFGHMZ

       画树求法:
       第一步,根据前序遍历的特点,我们知道根结点为G

       第二步,观察中序遍历ADEFGHMZ。其中root节点G左侧的ADEF必然是root的左子树,G右侧的HMZ必然是root的右子树。

       第三步,观察左子树ADEF,左子树的中的根节点必然是大树的root的leftchild。在前序遍历中,大树的root的leftchild位于root之后,所以左子树的根节点为D。

       第四步,同样的道理,root的右子树节点HMZ中的根节点也可以通过前序遍历求得。在前序遍历中,一定是先把root和root的所有左子树节点遍历完之后才会遍历右子树,并且遍历的左子树的第一个节点就是左子树的根节点。同理,遍历的右子树的第一个节点就是右子树的根节点。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <vector>
    using namespace std;
    typedef long long LL;
    const int INF=0x3f3f3f3f;
    const int maxn=50;
    int n,m,s,d;
    int a[maxn],b[maxn];
    struct Node
    {
        int l,r;
    }node[maxn];
    int buildtree(int la,int ra,int lb,int rb)
    {
        if(la>ra)
            return 0;
        int root=b[lb];
        int len1,len2;
        len1=la;
        while(a[len1]!=root)
            len1++;
        len2=len1-la;
        node[root].l=buildtree(la,len1-1,lb+1,lb+len2);
        node[root].r=buildtree(len1+1,ra,lb+len2+1,rb);
        return root;
    }
    void bfs(int root)
    {
        queue<int>q;
        vector<int>v;
        q.push(root);
        while(!q.empty())
        {
            int w=q.front();
            q.pop();
            if(w==0)
                break;
            v.push_back(w);
            if(node[w].l!=0)
                q.push(node[w].l);
            if(node[w].r!=0)
                q.push(node[w].r);
        }
        int len=v.size();
        for(int i=0;i<len;i++)
            printf("%d%c",v[i],i==len-1?'
    ':' ');
        return;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        for(int i=0;i<n;i++)
            scanf("%d",&b[i]);
        buildtree(0,n-1,0,n-1);
        int root=b[0];
        bfs(root);
        return 0;
    }

    6.  给后序和中序遍历,求层序遍历。

       思路和上面是一样的,主要是掌握建树的过程。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <vector>
    using namespace std;
    typedef long long LL;
    const int INF=0x3f3f3f3f;
    const int maxn=50;
    int n,m,s,d;
    int a[maxn],b[maxn];
    struct Node
    {
        int l,r;
    }node[maxn];
    int buildtree(int la,int ra,int lb,int rb)
    {
        if(la>ra)
            return 0;
        int root=a[rb];
        int len1,len2;
        len1=la;
        while(b[len1]!=root)
            len1++;
        len2=len1-la;
        node[root].l=buildtree(la,len1-1,lb,lb+len2-1);
        node[root].r=buildtree(len1+1,ra,lb+len2,rb-1);
        return root;
    }
    void bfs(int root)
    {
        queue<int>q;
        vector<int>v;
        q.push(root);
        while(!q.empty())
        {
            int w=q.front();
            q.pop();
            if(w==0)
                break;
            v.push_back(w);
            if(node[w].l!=0)
                q.push(node[w].l);
            if(node[w].r!=0)
                q.push(node[w].r);
        }
        int len=v.size();
        for(int i=0;i<len;i++)
            printf("%d%c",v[i],i==len-1?'
    ':' ');
        return;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)//先给的是后序
            scanf("%d",&a[i]);
        for(int i=0;i<n;i++)
            scanf("%d",&b[i]);
        buildtree(0,n-1,0,n-1);
        int root=a[n-1];
        bfs(root);
        return 0;
    }

    7.   给定二叉树,给出S型打印:

    void S_LevelOrderPrint(TreeNode t)
    {
        stack<TreeNode> s1;
        stack<TreeNode> s2;
        s1.push(t);
        while(!s1.empty() || !s2.empty())
        {
            if(!s1.empty())
            {
                while(!s1.empty())
                {
                    TreeNode tn = s1.top();
                    cout<<tn.val<<"";
                    s1.pop();
                    if(tn.right != null)
                        s2.push(tn.right);
                    if(tn.left != null)
                        s2.push(tn.left);
                }
            }
            else
            {
                while(!s2.empty())
                {
                    TreeNode tn = s2.top();
                    cout<<tn.val<<" ";
                    s2.pop();
                    if(tn.left != null)
                        s1.push(tn.left);
                    if(tn.right != null)
                        s1.push(tn.right);
                }
            }
        }
    }
  • 相关阅读:
    线性回归 r python 比较
    vps
    插桩 inline hook 动态二进制插桩的原理和基本实现过程
    duration of lease 1 0.5 0.875 DHCP 租借时间 续租时间 重新绑定时间
    单页应用 cookies处理
    websocket 无需通过轮询服务器的方式以获得响应 同步在线用户数 上线下线 抓包 3-way-handshake web-linux-shell 开发
    code_action
    mysql 表级锁
    mysql 表级锁
    块级标签和行级标签
  • 原文地址:https://www.cnblogs.com/jkzr/p/10594783.html
Copyright © 2011-2022 走看看