字符二叉树的遍历

对于以上二叉树
先序遍历为(根左右) : ABCDEFG
中序遍历为(左根右) : CBEDAFG
后序遍历为(左右根) : CEDBGFA
层序遍历:(从左往右、从上往下) ABFCDGE
以先序次序输入以上二叉树:
ABC##DE###F#G##
代码实现遍历操作:
#include <iostream>
#include <queue>
using namespace std;
typedef struct node
{
char data;
struct node *lchild;
struct node *rchild;
}BTNode,*tree;
tree root = NULL;
//按照先序次序输入二叉树的结点,bt为指向根结点的指针,建树需要&
void pre_crt(tree &bt)
{
char ch;
ch = getchar();
if (ch != '#')
{
bt = new node;//建立根结点
bt -> data = ch;
pre_crt(bt -> lchild);//建左子树
pre_crt(bt -> rchild);//建右子树
}
else bt = NULL;
}
void DLR(tree bt)
{
if (bt == NULL) return;
//先序遍历(根左右),遍历树不需要&
cout << bt -> data;
DLR(bt -> lchild);
DLR(bt -> rchild);
}
void LDR(tree bt)
{
if (bt == NULL) return;
//中序遍历(左根右)
LDR(bt -> lchild);
cout << bt -> data;
LDR(bt -> rchild);
}
void LRD(tree bt)
{
if (bt == NULL) return;
//后序遍历(左右根)
LRD(bt -> lchild);
LRD(bt -> rchild);
cout << bt -> data;
}
//层次遍历,传入根结点
void BTLeversearch(tree bt)
{
queue<tree> q;//tree指的是指针,即队列中存储指针
if (bt == NULL) return;
q.push(bt);//根结点入队
while (!q.empty())//队列非空
{
tree head = q.front();//获取队头元素
cout << head -> data;
if (head -> lchild) q.push(head -> lchild);
if (head -> rchild) q.push(head -> rchild);
q.pop();
}
}
int main()
{
pre_crt(root);//创建
DLR(root);//先序遍历
cout << endl;
LDR(root);//中序遍历
cout << endl;
LRD(root);//后序遍历
cout << endl;
BTLeversearch(root);
cout << endl;
return 0;
}
输入
ABC##DE###F#G##
输出
ABCDEFG
CBEDAFG
CEDBGFA
ABFCDGE
二叉树的构造
已知结点的先序序列为ABDGEHCF,中序序列为GDBHEACF。试构造出二叉树。
方法: 如果已知一棵二叉树的先序或者后序序列,就可以首先确定根结点(第一个或者最后一个结点),再根据中序序列确定左右子树如何分布。对于每棵子树,反复的从先序或者后序序列中找出根结点… …
【对于上例,二叉树的根结点为A】
构造出的二叉树如下:

普通树转换成二叉树
二叉树的操作和应用更广泛,在实际使用时,我们经常把普通树转换成二叉树进行操作。如何转换呢?一般方法如下:
- 第一步:将树中每个结点除了最左边的一个分支保留外,其余分支都去掉;
- 第二步:从最左边结点开始画一条线,把同一层上的兄弟结点都连起来;
- 第三步:以整棵树的根结点为轴心,将整棵树顺时针旋转45度。
举例:
下图是一棵普通的树

经过第一步之后,树变为如下形态:

经过第二步之后,树变为如下形态:
注意:只连接兄弟结点即可,故六号结点和七号结点不需要连接

经过第三步之后,树变为如下二叉树形态:

几道例题
例1.一棵完全二叉树的结点总数为18,其叶结点数为©
A.7
B.8
C.9
D.10
解:对于n层二叉树,其最多有2^n - 1个结点。由2 ^ n - 1 = 18,2 ^ 4 - 1 = 15 < 18,2 ^ 5 - 1 = 31 > 18,故n等于5,5层二叉树画图即可。不难发现,有9个叶子结点

例2.对任何一棵二叉树T,设n0、n1、n2分别是度数为0、1、2的顶点数,则下列判断中正确的是 (A)
A.n0 = n2+1
B.n1 = n0+1
C.n2 = n0+1
D.n2 = n1+1
送分题:性质的复习
例3.某二叉树的前序序列和后序序列正好相反,则该二叉树一定是 (B)的二叉树。
A.空或只有一个结点
B.高度等于其结点数
C.任一结点无左孩子
D.任一结点无右孩子
解法一:已知前序序列和后序序列相反
- 若去掉左子树,DLR=DR,LRD=RD,满足条件
- 若去掉右子树,DLR=DL,LRD=LD,满足条件
- C、D中带有一定二字,故排除C、D,A可以直接排除
解法二:对于下面的两棵二叉树,其先序遍历和后序遍历序列均相反,故C、D均可排除。但其都满足高度等于其结点数,故选B

先序遍历:1234
后序遍历:4321

先序遍历:1234
后序遍历:4321
例4.一个二叉树的先序遍历结果和中序遍历结果相同,则其所有非叶子节点必须满足的条件是(B)
A.只有左子树
B.只有右子树
C.节点的度为1
D.节点的度为2
解:
与上题类似,已知先序遍历和中序遍历相同,即DLR=LDR
- 若去掉右子树(只有左子树),则DL=LD,先序遍历和中序遍历相反,故排除A
- 若去掉左子树(只有右子树),则DR=DR,先序遍历和中序遍历相同,故选B
例5.下图为一个二叉树,请选出以下不是遍历二叉树产生的顺序序列的选项(BD)
A. ABCDEFIGJH
B. BDCAIJGHFE
C. BDCAIFJGHE
D. DCBJHGIFEA

解:
先序序列(根左右):ABCDEFIGJH
中序序列(左根右):BDCAIFJGHE
后序序列(左右根):DCBIJHGFEA
例6.中缀表达式A-(B+C/D)*E的后缀形式是(D)
A.AB-C+D/E*
B.ABC+D/-E*
C.ABCD/E*+-
D.ABCD/+E*-
提示:后缀表达式的操作符在操作数的后面
例7.中缀表达式1-(2+3)的前缀形式是(A)
A.-1+23
B.-12+3
C.-12+3
D.-+123
提示:前缀表达式的操作符在操作数的前面
二叉树的一些操作
- 求二叉树结点的个数
- 求二叉树叶子结点的个数
- 求二叉树的深度
- 判断一个结点是否在二叉树中
- 求第k层结点的个数
代码实现:
#include <iostream>
#include <queue>
using namespace std;
typedef struct node
{
char data;
struct node *lchild;
struct node *rchild;
}BTNode,*tree;
tree root = NULL;
//先序次序建树
void pre_crt(tree &bt)
{
char ch;
ch = getchar();
if (ch != '#')
{
bt = new node;
bt -> data = ch;
pre_crt(bt -> lchild);
pre_crt(bt -> rchild);
}
else bt = NULL;
}
//二叉树结点的个数
//二叉树结点的个数=左子树结点个数+右子树结点个数+1 (1为根结点)
int BTNodesize(tree bt)
{
if (bt == NULL) return 0;
return BTNodesize(bt -> lchild) + BTNodesize(bt -> rchild) + 1;
}
//二叉树叶子结点的个数
//二叉树叶子结点的个数=左子树叶子结点个数+右子树叶子结点个数
int BTNodeleaf(tree bt)
{
if (bt == NULL) return 0;
if (bt -> lchild == NULL && bt -> rchild == NULL) return 1;//叶子结点
return BTNodeleaf(bt -> lchild) + BTNodeleaf(bt -> rchild);
}
//求二叉树的深度
//二叉树的深度=max(左子树深度,右子树深度)+1 (1为根结点)
int BTDepth(tree bt)
{
if (bt == NULL) return 0;
int left = BTDepth(bt -> lchild);
int right = BTDepth(bt -> rchild);
return (left > right) ? (left + 1):(right + 1);
}
//判断一个结点x是否在二叉树中
bool BTFind(tree bt,char x)
{
bool temp;
if (bt == NULL) return false;//树空,返回false
if (bt -> data == x) return true;//递归出口:找到
temp = BTFind(bt -> lchild,x);//从左子树中查找x
if (temp) return true;
temp = BTFind(bt -> rchild,x);//从右子树中查找x
if (temp) return true;
return false;//没找到
}
//求第k层结点的个数
//当前树的第k层等于当前树的左子树的第k-1层(右子树同理)
int BTNodeKLevelSize(tree bt,int k)
{
if (bt == NULL) return 0;//空树
if (k == 1) return 1;//第一层之有根结点
return BTNodeKLevelSize(bt -> lchild,k - 1) + BTNodeKLevelSize(bt -> rchild,k - 1);
}
int main()
{
pre_crt(root);
cout << BTNodesize(root) << endl;//求二叉树结点的个数:7
cout << BTNodeleaf(root) << endl;//求二叉树叶子结点的个数:3
cout << BTDepth(root) << endl;//求二叉树的深度:4
if (BTFind(root,'D')) cout << "FIND" << endl;
else cout << "NOT FIND" << endl;//判断一个结点是否在二叉树中
cout << BTNodeKLevelSize(root,3) << endl;//求第3层结点的个数3:
return 0;
}
(以博客开头的第一棵树为例)
输入
ABC##DE###F#G##
输出
7
3
4
FIND
3
判断一颗二叉树是否为完全二叉树
算法思想:
- 借助
queue< int> q,将各个结点以层序遍历序列进行入队 - 如果发现
q.front()为NULL时,表示读取到了一个空结点,若它后面的结点都是NULL,则表示为完全二叉树 - 若它后面的结点出现不为NULL的情况,表示为非完全二叉树。
举例:
对于下图的一棵完全二叉树

对其进行层序遍历,得到1-2-5-3-4-null-null,按照这个顺序将结点依次入队,得到队列:

队列中的非NULL结点连续,故其是一棵完全二叉树
对于下图的非完全二叉树

对其进行层序遍历,得到1-2-5-3-4-null-6,按照这个顺序将结点依次入队,得到队列:

队列中的非NULL结点不连续,故其是一棵非完全二叉树
本文详细介绍了字符二叉树的先序、中序、后序和层序遍历算法,并通过代码实现。此外,还展示了如何根据先序和中序序列构造二叉树,以及一系列关于二叉树操作的练习题目,包括结点个数、叶子数、深度计算和判断等。

1602

被折叠的 条评论
为什么被折叠?



