二叉树的遍历

Posted jlyg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树的遍历相关的知识,希望对你有一定的参考价值。

  算法题目中有很多关于二叉树遍历的题目,以下就简要说一下可能的情况:

    1、已知先序和中序,求后序。比如先序1 2 3 4 6 7 5,中序2 1 6 4 7 3 5。主要步骤有:1、求当前父节点,该节点是当前先序序列的第一个。2、在中序节点中找出该父节点的位置(i,从0开始计数)。3、获得左右孩纸节点,中序的序列左右孩纸(0到i-1),(i,len-1),先序左右孩纸就是(1,i)(i+1,len-1)。整理出:左孩纸先序节点(0,i-1),中序序列节点(1,i),右孩纸的先序(i,len-1),中序是(i+1,len-1)。4分别对左右孩纸进行1步骤。

  

技术图片
#include<iostream>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<iterator>
#include<algorithm>
#include<cstring>
using namespace std;
struct Node
{
    int key;
    Node* left;
    Node* right;
    Node(){left=right=NULL;}
};
void post_travel(Node* root)
{
    if(root==NULL)
    {
        return;
    }
    post_travel(root->left);
    post_travel(root->right);
    printf("%d ",root->key);
}
Node* CreateTree(int* pre,int* inorder,int len)
{
    if(len<=0) return NULL;
    Node* node = new Node();
    node->key = *pre;
    if(len==1)
    {
        return node;
    }
    int i;
    for(i=0;i<len;++i)
    {
        if(inorder[i]==*pre)
        {
            break;
        }
    }
    node->left= CreateTree(pre+1,inorder,i);
    node->right = CreateTree(pre+i+1,inorder+i+1,len-i-1);
    return node;
}
int main()
{
    freopen("test.txt","r",stdin);
    int n;
    scanf("%d",&n);
    int pre[n],inorder[n];
    for(int i=0;i<n;++i)
    {
        scanf("%d",&pre[i]);
    }
    for(int i=0;i<n;++i)
    {
        scanf("%d",&inorder[i]);
    }
    Node* root = CreateTree(pre,inorder,n);
    post_travel(root);
    return 0;
}
View Code

 

     2、已知先序和后序,求中序(PAT原题1119)

    难点在先序和后序构造的树不一定唯一,当然也有可能唯一解。所以我们要知道什么时候二叉树不唯一,什么时候唯一呢?那例题来说1 2 3 4 6 7 5和2 6 7 4 5 3 1,我们第一步可以得到当前父节点1。然后如何判断左右孩纸呢。

先序1后面那个就是下一个节点(2),后序1前面那个就是下一个节点(3),这时候你发现2和3不一样,说明什么呢--其实说明一个是左孩纸,一个是有孩纸。然后从先序中找右孩纸(3)的节点位置,然后我们可以找到左右孩纸的两颗树的序:左孩纸树的先序序列2,后序也是2,右孩纸的先序序列就是3 4 6 7 5,后序序列是6 7 4 5 3。然后不断重复以上步骤就好了。

再看另一个例子:1 2 3 4、2 4 3 1。为什么不唯一呢,找左右孩纸序列,左孩纸2 右孩纸3 4(先序),4 3(后序)。然后对右孩纸进行递归,你会发现根节点是3,孩纸节点只有一个(4),然后你就不知道他是属于左节点还是右节点了,所以不唯一。

所以结论:先序和后序求中序,要求必须是孩纸节点要么没有,要么是2个,不能有任意节点只有一个孩纸节点。

技术图片
#include<iostream>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<iterator>
#include<algorithm>
#include<cstring>
using namespace std;
struct Node
{
    int key;
    Node* left;
    Node* right;
    Node()
    {
        left = right = NULL;
    }
};
bool bOnly = true;
Node* CreateTree(int* pre,int *post,int len)
{
    Node *node = new Node();
    node->key = *pre;
    if(len != 1)
    {
        //printf("len=%d
",len);
        if(*(pre+1) == *(post+len-2))
        {
            bOnly = false;
            node->left = CreateTree(pre+1,post,len-1);
        }
        else
        {
            int rightkey = *(post+len-2);
            int rightindex = 0;
            for(;rightindex<len;++rightindex)
            {
                if(rightkey == *(pre+rightindex))
                {
                    break;
                }
            }
            node->left = CreateTree(pre+1,post,rightindex-1);
            node->right = CreateTree(pre+rightindex,post+rightindex-1,len-rightindex);
        }
    }
    return node;
}
bool bFirst = true;
void inorder_travel(Node* root)
{
    if(root == NULL) return;
    inorder_travel(root->left);
    if(bFirst) bFirst = false;
    else printf(" ");
    printf("%d",root->key);
    inorder_travel(root->right);
}
int main()
{
    //freopen("test.txt","r",stdin);
    int n;
    scanf("%d",&n);
    int pre[n],post[n];
    for(int i=0;i<n;++i)
        scanf("%d",&pre[i]);
    for(int i=0;i<n;++i)
        scanf("%d",&post[i]);
    Node* root = CreateTree(pre,post,n);
    if(bOnly)
    {
        printf("Yes
");
    }
    else
    {
        printf("No
");
    }
    inorder_travel(root);
    printf("
");
    return 0;
}
View Code

 

        3、完全二叉树,已知中序排序求广度排序(PAT1064原题)

  1064题是用二叉搜索树,所以先需要排序一下,然后构造树就行了

技术图片
#include<iostream>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<iterator>
#include<algorithm>
#include<cstring>
using namespace std;
struct Node
{
    int key;
    Node* left;
    Node* right;
    Node(){left=right=NULL;}
};
int n;
int index2 = 0;
Node* CreateTree(int* a,int k)
{
    if(k>=n) return NULL;
    Node* node = new Node();
    node->left = CreateTree(a,2*k+1);
    node->key = a[index2++];
    node->right = CreateTree(a,2*k+2);
    return node;
}
bool bFirst = true;
void level_travel(vector<Node*> vn)
{
    if(vn.size()==0) return;
    vector<Node*> vnnext;
    for(int i=0;i<vn.size();++i)
    {
        if(bFirst) bFirst = false;
        else printf(" ");
        printf("%d",vn[i]->key);
        if(vn[i]->left) vnnext.push_back(vn[i]->left);
        if(vn[i]->right) vnnext.push_back(vn[i]->right);
    }
    level_travel(vnnext);
}
int main()
{
    //freopen("test.txt","r",stdin);
    scanf("%d",&n);
    int inorder[n];
    for(int i=0;i<n;++i)
        scanf("%d",&inorder[i]);
    sort(inorder,inorder+n);
    Node* root = CreateTree(inorder,0);
    vector<Node*> vn;
    vn.push_back(root);
    level_travel(vn);
    return 0;
}
View Code

 

以上是关于二叉树的遍历的主要内容,如果未能解决你的问题,请参考以下文章

二叉树的遍历

讲透学烂二叉树:二叉树的遍历图解算法步骤及JS代码

二叉树(2.二叉树的遍历和实现)

根据二叉树的前序遍历和中序遍历构建二叉树的c语言完整代码

通过遍历序列构造二叉树(扩展二叉树的先序先序和中序后序和中序层序和中序)附可执行完整代码

代码题— 二叉树的层次遍历