十七、二叉树的建立与基本操作
十七、二叉树的建立与基本操作
文章目录
- 十七、二叉树的建立与基本操作
- 题目描述
- 解题思路
- 上机代码
- 一点建议
题目描述
编写程序实现二叉树的如下操作:
输入:
按完全二叉树的层次关系给出二叉树的遍历序列(#表示虚结点,数据结点为单一字符)。
输出:
二叉树的凹入表示
二叉树的先序序列、中序序列、后序序列
二叉树叶子结点个数
左、右子树相互交换后的二叉树的凹入表示
左、右子树相互交换后的二叉树的先序序列、中序序列、后序序列。
说明:
在输出凹入表示的二叉树时,先输出根结点,然后依次输出左右子树,上下层结点之间相隔 3 个空格。
| 测试用例 1 | abc#de | BiTree a b d c e pre_sequence : abdce in_sequence : bdaec post_sequence : dbeca Number of leaf: 2 BiTree swapped a c e b d pre_sequence : acebd in_sequence : ceadb post_sequence : ecdba | 1秒 | 64M | 0 |
| 测试用例 2 | abcdefg | BiTree a b d e c f g pre_sequence : abdecfg in_sequence : dbeafcg post_sequence : debfgca Number of leaf: 4 BiTree swapped a c g f b e d pre_sequence : acgfbed in_sequence : gcfaebd post_sequence : gfcedba | 1秒 | 64M | 0 |
解题思路
二叉链表的存储表示在教材的 127 页进行了介绍
typedef struct BiTNode {char data; //结点数据struct BiTNode *lchild, *rchild; //左右孩子指针 }BiTNode, *BiTree;仔细阅读并理解题目,我们重点需要完成四个步骤:
1、按完全二叉树的层次关系建立一颗二叉树。给出二叉树的层次序列,那么我们需要借助队列来建立这颗二叉树。(层次序列都适合用队列处理,类似于 BFS 的思想)
2、二叉树的凹入表示,按照层次关系进行输出。第一层没有空格,第二层一个 tab(四个空格),第二层两个 tab ······
3、二叉树的三种遍历序列很适合用递归的方式来遍历求解
- 先序遍历,也叫前序遍历
- 访问根结点
- 先序遍历左子树
- 先序遍历右子树
- 中序遍历
- 中序遍历左子树
- 访问根结点
- 中序遍历右子树
- 后序遍历
- 后序遍历左子树
- 后序遍历右子树
- 访问根结点
4、统计二叉树中叶子结点个数。叶子结点的左右指针域不指向任何结点,要么是 \0,要么是 #,根据这个条件可以找出叶子结点。然后统计叶子结点又得遍历一遍二叉树,所以将叶子结点的统计和二叉树的其中一个遍历结合操作起来更省事。
至于左右子树交换后的各种表示,对二叉树表示的顺序进行简单的翻转就可以实现,代码的编写就是左右次序交换的问题。
例如,对二叉树的中序遍历,应该先输出左子树,接着输出该结点的值,最后输出右子树。左右子树交换后的二叉树的中序遍历,应该先输出右子树,接着输出该结点的值,最后输出左子树。
上机代码
#include<cstdio> #include<iostream> #include<queue> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std;//二叉树的存储表示 typedef struct BiTNode {char data;struct BiTNode *lchild;struct BiTNode *rchild; }BiTNode, *BiTree;queue<BiTree>q; //辅助队列 int counts = 0; //统计叶子结点数目void createBiTree(); //建立二叉树 void visit(BiTree R); //访问结点 void print(BiTree R, int n); //输出二叉树 void pre_sequence(BiTree R); //先序遍历 void in_sequence(BiTree R); //中序遍历 void post_sequence(BiTree R); //后序遍历 /* 左右子树交换后的各种表示 */ void swap_print(BiTree R, int n); void swap_pre_sequence(BiTree R); void swap_in_sequence(BiTree R); void swap_post_sequence(BiTree R);int main() {BiTree bit;bit = (BiTree)malloc(sizeof(BiTNode));q.push(bit);//建树 createBiTree();//打印二叉树printf("BiTree\n");print(bit, 0);//先序 printf("pre_sequence : ");pre_sequence(bit);printf("\n");//中序 printf("in_sequence : ");in_sequence(bit);printf("\n");//后序 printf("post_sequence : ");post_sequence(bit);printf("\n");//叶子结点数目printf("Number of leaf: %d\n", counts);/* 翻转 */ printf("BiTree swapped\n");swap_print(bit, 0);printf("pre_sequence : ");swap_pre_sequence(bit);printf("\n");printf("in_sequence : ");swap_in_sequence(bit);printf("\n");printf("post_sequence : ");swap_post_sequence(bit);printf("\n");return 0; }void createBiTree() {char c;BiTree T, N;while (!q.empty()){scanf("%c", &c);if (c == '\n') //换行符结束读取break;T = q.front();q.pop();T->data = c; //结点赋值//左子树表示N = (BiTree)malloc(sizeof(BiTNode));N->data = '\0';T->lchild = N;q.push(N);//右子树表示N = (BiTree)malloc(sizeof(BiTNode));N->data = '\0';T->rchild = N;q.push(N);} } void visit(BiTree R) {//结点不为空则输出if (R->data != '#'&&R->data != '\0')cout << R->data; } void print(BiTree R, int n) {if (R->data != '#'&&R->data != '\0'){int i = 1;while (i <= n) //第几层就输几个tab{cout << " ";i++;}visit(R);cout << endl;//一层一层往下找n++;print(R->lchild, n);print(R->rchild, n);} } void pre_sequence(BiTree R) {if (R->data != '#'&&R->data != '\0'){visit(R);pre_sequence(R->lchild);pre_sequence(R->rchild);} } void in_sequence(BiTree R) {if (R->data != '#'&&R->data != '\0'){in_sequence(R->lchild);/* 统计叶子结点和中序遍历结合 */if ((R->lchild->data == '#' || R->lchild->data == '\0') && (R->rchild->data == '#' || R->rchild->data == '\0'))counts++;visit(R);in_sequence(R->rchild);} } void post_sequence(BiTree R) {if (R->data != '#'&&R->data != '\0'){post_sequence(R->lchild);post_sequence(R->rchild);visit(R);} } void swap_print(BiTree R, int n) {//翻转后的写法与原来一模一样,只是换了顺序而已if (R->data != '#'&&R->data != '\0'){int i = 1;while (i <= n){cout << " ";i++;}visit(R);cout << endl;n++;swap_print(R->rchild, n);swap_print(R->lchild, n);} } void swap_pre_sequence(BiTree R) {if (R->data != '#'&&R->data != '\0'){visit(R);swap_pre_sequence(R->rchild);swap_pre_sequence(R->lchild);} } void swap_in_sequence(BiTree R) {if (R->data != '#'&&R->data != '\0'){swap_in_sequence(R->rchild);visit(R);swap_in_sequence(R->lchild);} } void swap_post_sequence(BiTree R) {if (R->data != '#'&&R->data != '\0'){swap_post_sequence(R->rchild);swap_post_sequence(R->lchild);visit(R);} }一点建议
二叉树的建立和遍历序列,在之后的学习中还会继续遇到,建议大家一定要自己总结出一个自己认为好用的模板。
比如编写一个利用层次序列建立二叉树的模板,下次又遇到的时候可以直接使用模板而不是再编写一遍。同样地,三种遍历序列的模板也是很需要的,递归方式和非递归方式都要掌握。
总结
以上是生活随笔为你收集整理的十七、二叉树的建立与基本操作的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 十六、广义表的建立与基本操作
- 下一篇: 十八、二叉树遍历序列还原