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

Posted 薛定谔的猫ovo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通过遍历序列构造二叉树(扩展二叉树的先序先序和中序后序和中序层序和中序)附可执行完整代码相关的知识,希望对你有一定的参考价值。

二叉树的构造

 可以构建一棵二叉树的几个方法:

  • 扩展二叉树的先序遍历序列
  • 前序遍历序列和中序遍历序列
  • 后序遍历序列和中序遍历序列
  • 层序遍历序列和中序遍历序列

 注意,只有前序遍历序列和后序遍历序列是不能唯一的确定一棵二叉树的。


扩展二叉树的先序遍历序列构造二叉树

题目描述:
 在二叉树的所有空指针位置加入虚拟结点,就构成扩展二叉树。二叉树原有的结点称为内结点,新增的虚拟节点称为外结点
 设已知扩展二叉树的先序遍历序列,并用在原二叉树中不可能出现的值作为虚拟结点的值,如 “#” 表示外结点的值。
 设计一个算法,使用这样一个先序遍历序列,建立树的二叉链表。

算法思想:
 每读入一个值,若该值为"#",则返回空,继续读入下一个值;如果该值不为"#",那么就为它建立结点,结点值为该值,然后将该结点作为根结点,其地址通过函数的引用型参数root直接链接到作为实际参数的指针中。然后分别对左、右子树递归的建立子树。

实现代码:

//扩展二叉树的先序遍历序列
void BuildTree_Pre(BNode * & root, char pre[], int & i){
    if(pre[i] == '#'){ //外结点,即空结点
        i++;
        root = NULL;
    }else{
        root = (BNode *)malloc(sizeof(BNode)); //建立根结点
        root->data = pre[i];
        i++;
        BuildTree_Pre(root->lchild, pre, i); //递归建立左子树
        BuildTree_Pre(root->rchild, pre, i); //递归建立右子树
    }
}

另外,还有一种写法请参照二叉树遍历应用之根据前序遍历建树
思路是一致的,如果不理解引用型参数的可以参照这篇文章中的写法。

实例:
在这里插入图片描述

 如上图所示,所有结点值为"#"的结点位于原二叉树的空子树结点的位置,按照先序遍历所得到的先序遍历序列为ABC##DE#G##F###。
 若要建立如上所示的二叉树,则输入就应为ABC##DE#G##F###。


 这里给出可执行的完整代码,为了验证构造的二叉树,构造完二叉树后,再输出其层序遍历的结果。

#include<bits/stdc++.h>
using namespace std;

typedef struct BNode{
    char data;
    struct BNode *lchild;
    struct BNode *rchild;
}BNode;

//扩展二叉树的先序遍历序列
void BuildTree_Pre(BNode * & root, char pre[], int & i){
    if(pre[i] == '#'){ //外结点,即空结点
        i++;
        root = NULL;
    }else{
        root = (BNode *)malloc(sizeof(BNode)); //建立根结点
        root->data = pre[i];
        i++;
        BuildTree_Pre(root->lchild, pre, i); //递归建立左子树
        BuildTree_Pre(root->rchild, pre, i); //递归建立右子树
    }
}

//层序遍历
void levelOrder(BNode *root){
    queue<BNode *> treenode;
    if(root != NULL)
        treenode.push(root);
    while(!treenode.empty()){
        BNode *p = treenode.front();
        treenode.pop();
        printf("%c ",p->data);
        if(p->lchild != NULL)
            treenode.push(p->lchild);
        if(p->rchild != NULL)
            treenode.push(p->rchild);
    }
}


int main(){
    char pre[100];
    BNode *root;;
    scanf("%s",pre);
    int i = 0;
    BuildTree_Pre(root, pre, i); 
    levelOrder(root);
    return 0;
}

 执行结果:
在这里插入图片描述



先序遍历序列和中序遍历序列构造二叉树

题目描述:
 给定一棵二叉树的先序遍历序列pre[s1…t1]和中序遍历序列in[s2…t2],设二叉树采用二叉链表存储,设计一个算法构造这棵二叉树。

算法思想:
 算法的实现步骤如下:
 1)根据先序遍历序列确定树的根结点;
 2)根据根结点在中序序列中的次序划分出二叉树的左子树、右子树包含哪些结点,
 然后根据左、右子树结点在先序序列中的次序确定子树的根结点,即回到步骤1)。
 重复上述步骤,直到每棵子树仅有一个结点(该子树的根结点)为止。
如下图所示:
 若前序遍历序列为:ABCDEFGHI
 中序遍历序列为:BCAEDGHFI
在这里插入图片描述

实现代码:

//先序遍历和中序遍历建树
BNode *PreInCreate(char pre[], char in[], int s1, int t1, int s2, int t2){
    //s1,t1为先序遍历序列的第一个结点和最后一个结点的下标
    //s2,t2为中序遍历序列的第一个结点和最后一个结点的下标
    //初始时s1=s2=0, t1=t2=n-1
    BNode *root = (BNode *)malloc(sizeof(BNode)); //建立根结点
    root->data = pre[s1]; //根结点
    int i;
    for(i=s2; in[i]!=root->data; i++); //找根结点在中序遍历序列中的位置
    int llen = i-s2; //左子树长度
    int rlen = t2-i; //右子树长度
    if(llen != 0) //递归建立左子树
        root->lchild = PreInCreate(pre, in, s1+1, s1+llen, s2, s2+llen-1);
    else //左子树为空
        root->lchild = NULL;
    if(rlen != 0)//递归建立右子树
        root->rchild = PreInCreate(pre, in, t1-rlen+1, t1, t2-rlen+1, t2);
    else //右子树为空
        root->rchild = NULL; 
    return root;
}

 或者,也可以使用引用型参数进行实现,实现的思路是一致的。

void PreInCreate2(BNode *&root, char pre[], char in[], int s1, int t1, int s2, int t2){
    if(s1<=t1){
        root = (BNode *)malloc(sizeof(BNode));
        root->data = pre[s1];
        root->lchild = NULL;
        root->rchild = NULL;
        int i;
        for(i=0; in[i]!=root->data; i++);
        int llen = i-s2; //左子树长度
        int rlen = t2-i; //右子树长度
        PreInCreate2(root->lchild, pre, in, s1+1, s1+llen, s2, s2+llen-1); //递归建立左子树
        PreInCreate2(root->rchild, pre, in, t1-rlen+1, t1, t2-rlen+1, t2); //递归建立右子树
    }
}

 这里给出可执行的完整代码,为了验证构造的二叉树,构造完二叉树后,再输出其层序遍历的结果。

#include<bits/stdc++.h>
using namespace std;

typedef struct BNode{
    char data;
    struct BNode *lchild;
    struct BNode *rchild;
}BNode;

//层序遍历
void levelOrder(BNode *root){
    queue<BNode *> treenode;
    if(root != NULL)
        treenode.push(root);
    while(!treenode.empty()){
        BNode *p = treenode.front();
        treenode.pop();
        printf("%c ",p->data);
        if(p->lchild != NULL)
            treenode.push(p->lchild);
        if(p->rchild != NULL)
            treenode.push(p->rchild);
    }
}

//先序遍历和中序遍历建树
BNode *PreInCreate(char pre[], char in[], int s1, int t1, int s2, int t2){
    //s1,t1为先序遍历序列的第一个结点和最后一个结点的下标
    //s2,t2为中序遍历序列的第一个结点和最后一个结点的下标
    //初始时s1=s2=0, t1=t2=n-1
    BNode *root = (BNode *)malloc(sizeof(BNode)); //建立根结点
    root->data = pre[s1]; //根结点
    int i;
    for(i=s2; in[i]!=root->data; i++); //找根结点在中序遍历序列中的位置
    int llen = i-s2; //左子树长度
    int rlen = t2-i; //右子树长度
    if(llen != 0) //递归建立左子树
        root->lchild = PreInCreate(pre, in, s1+1, s1+llen, s2, s2+llen-1);
    else //左子树为空
        root->lchild = NULL;
    if(rlen != 0)//递归建立右子树
        root->rchild = PreInCreate(pre, in, t1-rlen+1, t1, t2-rlen+1, t2);
    else //右子树为空
        root->rchild = NULL; 
    return root;
}

void PreInCreate2(BNode *&root, char pre[], char in[], int s1, int t1, int s2, int t2){
	//s1,t1为先序遍历序列的第一个结点和最后一个结点的下标
    //s2,t2为中序遍历序列的第一个结点和最后一个结点的下标
    //初始时s1=s2=0, t1=t2=n-1
    if(s1<=t1){
        root = (BNode *)malloc(sizeof(BNode));
        root->data = pre[s1];
        root->lchild = NULL;
        root->rchild = NULL;
        int i;
        for(i=0; in[i]!=root->data; i++);
        int llen = i-s2; //左子树长度
        int rlen = t2-i; //右子树长度
        PreInCreate2(root->lchild, pre, in, s1+1, s1+llen, s2, s2+llen-1); //递归建立左子树
        PreInCreate2(root->rchild, pre, in, t1-rlen+1, t1, t2-rlen+1, t2); //递归建立右子树
    }
}


int main(){
    char pre[100];
    char in[100];
    BNode *root;
    BNode *root2;
    int s1=0,s2=0;
    int t1,t2;
    scanf("%s",pre);
    scanf("%s",in);
    t1 = strlen(pre)-1;
    t2 = strlen(in)-1;
    root = PreInCreate(pre, in, s1, t1, s2, t2);
    levelOrder(root);
    printf("\\n");
    PreInCreate2(root2, pre, in, s1, t1, s2, t2);
    levelOrder(root2);
    return 0;
}

 执行结果:
在这里插入图片描述



后序遍历序列和中序遍历序列构造二叉树

题目描述:
 给定一棵二叉树的后序遍历序列post[s1…t1]和中序遍历序列in[s2…t2],设二叉树采用二叉链表存储,设计一个算法构造这棵二叉树。

算法思想:
 算法的实现步骤如下:
 1)根据后序遍历序列确定树的根结点;
 2)根据根结点在中序序列中的次序划分出二叉树的左子树、右子树包含哪些结点,
 然后根据左、右子树结点在后序序列中的次序确定子树的根结点,即回到步骤1)。
 重复上述步骤,直到每棵子树仅有一个结点(该子树的根结点)为止。
注意,这里与先序序列和中序序列构造二叉树的不同之处在于,先递归建立右子树,再递归建立左子树,这是由于
如下图所示:
 若后序遍历序列为:CBEHGIFDA
 中序遍历序列为:BCAEDGHFI
在这里插入图片描述

实现代码:

BNode *PostInCreate(char post[], char in[], int s1, int t1, int s2, int t2){
    //s1,t1为后序遍历序列的第一个结点和最后一个结点的下标
    //s2,t2为中序遍历序列的第一个结点和最后一个结点的下标
    //初始时s1=s2=0, t1=t2=n-1
    BNode *root = (BNode *)malloc(sizeof(BNode)); //建立根结点
    root->data = post[t1]; //根结点
    int i;
    for(i=s2; in[i]!=root->data; i++); //找根结点在中序遍历序列中的位置
    int llen = i-s2; //左子树长度
    int rlen = t2-i; //右子树长度
    if(llen != 0) //递归建立左子树
        root->lchild = PostInCreate(post, in, s1, s1+llen-1, s2, s2+llen-1);
    else //左子树为空
        root->lchild = NULL;
    if(rlen != 0) //递归建立右子树
        root->rchild = PostInCreate(post, in, t1-rlen, t1-1, t2-rlen+1, t2);
    else //右子树为空
        root->rchild = NULL;
    return root;
}

 或者,也可以使用引用型参数进行实现,实现的思路是一致的。

void PostInCreate2(BNode *&root, char post[], char in[], int s1, int t1, int s2, int t2){
    //s1,t1为后序遍历序列的第一个结点和最后一个结点的下标
    //s2,t2为中序遍历序列的第一个结点和最后一个结点的下标
    //初始时s1=s2=0, t1=t2=n-1
    if(s1<=t1){
        root = (BNode *)malloc(sizeof(BNode));
        root->data = post[t1];
        root->lchild = NULL;
        root->rchild = NULL;
        int i;
        for(i=0; in[i]!=root->data; i++); //找中序遍历序列中的根结点的位置
        int llen = i-s2; //左子树长度
        int rlen = t2-i; //右子树长度
        PostInCreate2(root->lchild, post, in, s1, s1+llen-1, s2, s2+llen-1); //递归建立左子树
        PostInCreate2(root->rchild, post, in, t1-rlen, t1-1, t2-rlen+1, t2); //递归建立右子树
    }
}

 这里给出可执行的完整代码,为了验证构造的二叉树,构造完二叉树后,再输出其层序遍历的结果。

#include<bits/stdc++.h>
using namespace std;

typedef struct BNode{
    char data;
    struct BNode *lchild;
    struct BNode *rchild;
}BNode;

//层序遍历
void levelOrder(BNode *root){
    queue<BNode *> treenode;
    if(root != NULL)
        treenode.push(root);
    while(!treenode.empty()){
        BNode *p = treenode.front();
        treenode.pop();
        printf("%c ",p->data);
        if(p->lchild != NULL)
            treenode.push(p->lchild);
        if(p->rchild != NULL)
            treenode.push(p->rchild);
    }

以上是关于通过遍历序列构造二叉树(扩展二叉树的先序先序和中序后序和中序层序和中序)附可执行完整代码的主要内容,如果未能解决你的问题,请参考以下文章

已知一个二叉树的先序序列和中序序列,怎么求它的后序序列

已知二叉树的先序序列和中序序列怎么求后序序列?不是基于C++的,要在TC环境下能运行的,各位能人帮帮忙吧

pascal给出一棵二叉树的中序与后序排列。求出它的先序排列(帮忙解释一下程序)

给出二叉树的先序和中序遍历,给出后序遍历

已知二叉树的先序遍历序列和中序遍历序列,求后序遍历序列。

已知二叉树的先序遍历序列和中序遍历序列,输出该二叉树的后序遍历序列