hnust 1802: 二叉树遍历2
题目描述
二叉树的前序、中序、后序遍历的定义:
前序遍历:对任一子树,先访问跟,然后遍历其左子树,最后遍历其右子树;
中序遍历:对任一子树,先遍历其左子树,然后访问根,最后遍历其右子树;
后序遍历:对任一子树,先遍历其左子树,然后遍历其右子树,最后访问根。
给定一棵二叉树的前序遍历和中序遍历,求其后序遍历(提示:给定前序遍历与中序遍历能够唯一确定后序遍历)。
拷贝下面的代码,完成相应的函数。
//给定前序遍历和中序遍历,求其后序遍历
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
using namespace std;typedef char TElemType;
//二叉树的二叉链表存储表示
typedef struct BiTNode {TElemType data; //结点数据域struct BiTNode *lchild, *rchild; //左右孩子指针
} BiTNode, *BiTree;//根据先序序列pre[pre_low..pre_low+len-1]和中序序列in[in_low..in_low+len-1]建树t
void BuildTree(BiTree& t, char pre[], int pre_low, char in[], int in_low, int len)
{/****在此下面完成代码************//*********************************/
}
// 后序遍历的递归算法
void PostOrderTraverse(BiTree t)
{/****在此下面完成代码************//*********************************/
}void DestroyBitree(BiTree& t)
{/****在此下面完成代码************//*********************************/
}int main()
{char pre[30], in[30];BiTree t = NULL;while(cin >> pre) {cin >> in;BuildTree(t, pre, 0, in, 0, strlen(in));PostOrderTraverse(t);DestroyBitree(t);cout << endl;}
}
输入
两个字符串,其长度n均小于等于26。
第一行为前序遍历,第二行为中序遍历。
二叉树中的结点名称以大写字母表示:A,B,C…最多26个结点。
输出
输入样例可能有多组,对于每组测试样例,
输出一行,为后序遍历的字符串。
样例输入 Copy
ABC
CBA
ABCDEFG
DCBAEFG
样例输出 Copy
CBA
DCBGFEA
代码解析
这段C++代码实现了根据先序序列和中序序列构建二叉树,后序遍历该二叉树,并最终销毁二叉树的功能。
1. 数据结构定义
BiTNode:定义了二叉树的节点结构,包含数据域data和指向左右孩子的指针lchild,rchild。BiTree:二叉树的类型定义,指向BiTNode的指针。
2. 函数 BuildTree
- 作用:根据先序序列
pre和中序序列in构建二叉树。 - 输入参数:先序序列的起始索引
pre_low,中序序列的起始索引in_low,序列长度len。 - 过程:
- 如果序列长度小于等于0,返回
NULL。 - 否则,创建一个新的节点,其数据为先序序列的第一个元素。
- 在中序序列中找到根节点的位置。
- 递归地使用先序序列的子序列和中序序列的相应子序列构建左子树和右子树。
- 如果序列长度小于等于0,返回
3. 函数 PostOrderTraverse
- 作用:后序遍历二叉树。
- 过程:
- 如果树为空,返回。
- 否则,先递归遍历左子树,然后递归遍历右子树,最后访问根节点。
4. 函数 DestroyBitree
- 作用:销毁二叉树,释放所有节点的内存。
- 过程:
- 如果树为空,返回。
- 否则,递归地销毁左子树和右子树,然后释放当前节点的内存,并将指针设置为
NULL。
5. 主函数 main
- 使用
while循环读取先序序列和中序序列。 - 调用
BuildTree函数构建二叉树。 - 调用
PostOrderTraverse函数进行后序遍历。 - 调用
DestroyBitree函数销毁二叉树。 - 打印换行符,开始下一轮遍历。
解题过程分析
问题分析
在计算机科学中,二叉树是一种基本的数据结构,而根据先序序列和中序序列构建二叉树是二叉树问题中的一个经典问题。本题要求实现这一功能,并进行后序遍历。
构建二叉树
构建二叉树的关键在于理解先序序列和中序序列的特点:
- 先序序列的第一个元素是树的根节点。
- 在中序序列中,根节点左边的部分是左子树,右边的部分是右子树。
利用这些特点,我们可以递归地构建整棵树。
后序遍历
后序遍历是二叉树遍历的一种方式,其顺序是:先递归遍历左子树,然后递归遍历右子树,最后访问根节点。这种遍历方式有助于我们访问树中的所有节点。
销毁二叉树
由于二叉树的节点是通过动态内存分配创建的,因此在不需要二叉树时,需要手动释放每个节点占用的内存,以避免内存泄漏。
代码分解
- 数据结构定义:定义了二叉树节点的结构
BiTNode和二叉树类型BiTree。 - 构建函数:
BuildTree函数使用递归方法根据先序和中序序列构建二叉树。 - 遍历函数:
PostOrderTraverse函数使用递归方法实现后序遍历。 - 销毁函数:
DestroyBitree函数使用递归方法销毁二叉树,释放所有节点的内存。 - 主函数:在
main函数中,使用循环读取输入,构建二叉树,进行遍历,然后销毁二叉树。
总结
本文通过一段C++代码,展示了如何根据先序序列和中序序列构建二叉树,以及如何进行后序遍历和销毁二叉树。这些操作是数据结构中的基本技能,对于理解和掌握二叉树的概念非常有帮助。
注意事项
- 在读取输入时,要注意处理字符串的结束符。
- 在构建二叉树时,确保正确处理空树的情况。
- 在销毁二叉树时,要确保所有节点的内存都被正确释放。
- 使用递归方法时,要注意避免栈溢出的风险,尤其是在处理大型数据结构时。
部分代码
//根据先序序列pre[pre_low..pre_low+len-1]和中序序列in[in_low..in_low+len-1]建树t
void BuildTree(BiTree& t, char pre[], int pre_low, char in[], int in_low, int len)
{/****在此下面完成代码************/if(len<=0)t=NULL;//长度为0,t就没有数据啦else{t=new BiTNode;t->data=pre[0];//先序的第一个是这一段的根char root=pre[0];//存根int i;for(i=0;i<len;i++){//从中序中找到这个根的位置iif(in[i]==root)break;}BuildTree(t->lchild,pre+1,0,in,0,i);//i位置左边的数值是这一段的左子树BuildTree(t->rchild,pre+i+1,0,in+i+1,0,len-(i+1));//右边是右子树}/*********************************/
}
// 后序遍历的递归算法
void PostOrderTraverse(BiTree t)
{/****在此下面完成代码************/if(!t)return;else{PostOrderTraverse(t->lchild);PostOrderTraverse(t->rchild);cout<<t->data;}/*********************************/
}
void DestroyBitree(BiTree& t)
{/****在此下面完成代码************/if(!t)return ;else{if(t->lchild)DestroyBitree(t->lchild);if(t->rchild)DestroyBitree(t->rchild);delete t;t=NULL;}/*********************************/
}
AC代码
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
using namespace std;typedef char TElemType;
//二叉树的二叉链表存储表示
typedef struct BiTNode {TElemType data; //结点数据域struct BiTNode *lchild, *rchild; //左右孩子指针
} BiTNode, *BiTree;//根据先序序列pre[pre_low..pre_low+len-1]和中序序列in[in_low..in_low+len-1]建树t
void BuildTree(BiTree& t, char pre[], int pre_low, char in[], int in_low, int len)
{/****在此下面完成代码************/if(len<=0)t=NULL;//长度为0,t就没有数据啦else{t=new BiTNode;t->data=pre[0];//先序的第一个是这一段的根char root=pre[0];//存根int i;for(i=0;i<len;i++){//从中序中找到这个根的位置iif(in[i]==root)break;}BuildTree(t->lchild,pre+1,0,in,0,i);//i位置左边的数值是这一段的左子树BuildTree(t->rchild,pre+i+1,0,in+i+1,0,len-(i+1));//右边是右子树}/*********************************/
}
// 后序遍历的递归算法
void PostOrderTraverse(BiTree t)
{/****在此下面完成代码************/if(!t)return;else{PostOrderTraverse(t->lchild);PostOrderTraverse(t->rchild);cout<<t->data;}/*********************************/
}void DestroyBitree(BiTree& t)
{/****在此下面完成代码************/if(!t)return ;else{if(t->lchild)DestroyBitree(t->lchild);if(t->rchild)DestroyBitree(t->rchild);delete t;t=NULL;}/*********************************/
}int main()
{char pre[30], in[30];BiTree t = NULL;while(cin >> pre) {cin >> in;BuildTree(t, pre, 0, in, 0, strlen(in));PostOrderTraverse(t);DestroyBitree(t);cout << endl;}
}