第五章 树和二叉树(5.4-5.5.1)
5.4 二叉树的性质和存储结构
5.4.1二叉树的性质
性质1:第i层上至多有2^{i-1}个结点(i从1开始增加)
性质2:深度为 l 的二叉树至多有2^{l}-1个结点
二叉树的深度为l,每一层上的结点数目为2^{i-1},由等比数列的求和公式可以得出结果:
性质3:对于任何一棵二叉树,若叶子结点数为N0,度为2的结点数为N2,则
由树的基本定义与结构中可以了解得叶子结点数与度的概念,假设二叉树中的结点总数为N,同时度为1的结点数为N1,有以下等式:

根据度的概念可以得知,结点向下延伸的直线连接至另一个结点,向下关联的结点数目就是结点的度,而每一个结点仅仅只有一条由上向下连接的直线。所以,所有的结点数目之和等于连接的直线数加1(1代表顶端的根结点),度为2的点向下发出的直线数目为2,度为1的结点发出的数目为1:
综合以上两式,得出结论为:
注:完全二叉树与满二叉树的区别,满二叉树是指深度为l,并且具有2^{l}-1个结点的二叉树,完全二叉树是指在深度为l, 结点数为n的二叉树中,当且仅当每一个结点与深度为l的满二叉树中编号为1至n的结点一一对应时,该二叉树称作完全二叉树(即二叉树若存在第l层,其上l-1层必定是满二叉树)。两种二叉树的示意图如下:
性质4:具有n个结点的完全二叉树的深度k为
假设完全二叉树的深度为k,又因为完全二叉树的性质,导致其节点数目n处于2{k-1}-1至2-1之间,得出由于k是整数的缘故,所以
性质5: 若对一棵有n个结点的完全二叉树结点按每一层从左到右的顺序来编号,对于任何一个编号为i的结点均有以下结论:
(1) i = 1,则 i 是二叉树的根,无双亲。若i >1,则双亲是编号为 的结点
(2)若 2i> n,结点i无左孩子,否则,其左孩子结点的编号为2i
(3)若2i+1>n,则结点i 无右孩子,否则其右孩子是节点2i+1
以图“完全二叉树”为例,编号为3的结点无右孩子,编号为4、5、6的结点无左孩子
5.4.2二叉树的存储结构
1.顺序存储结构
#define MAXTSIZE 100 //二叉树的最大结点数
typedef TElemType SqBiTree[MAXTSIZE];//0号单元存储根结点
SqBiTree bt; //数组bt
2.链式存储结构
//二叉树的二叉链表存储表示
typedef struct BiTNode{
TElemType data; //结点数据域
struct BiTNode *lchild,*rchild; //左右孩子指针
}BiTNode,*BiTree;
5.5遍历二叉树和线索二叉树
5.5.1遍历二叉树
1.遍历二叉树的算法描述
1.1先序遍历
若二叉树为空,则:空操作
否则:
访问根结点(D);
先序遍历左子树(L);
先序遍历右子树(R);
void PreOrderTraverse(BiTree T)
{
if (T) //非空二叉树
{
printf("%d", T->data); //访问根结点
PreOrderTraverse(T->lchild); //递归遍历左子树
PreOrderTraverse(T->rchild); //递归遍历右子树
}
}
1.2.中序遍历
若二叉树为空,则:空操作
否则:
中序遍历左子树(L);
访问根结点(D);
中序遍历右子树(R);
void InOrderTraverse(BiTree T)
{
if (T) //非空二叉树
{
InOrderTraverse(T->lchild); //递归遍历左子树
printf("%d", T->data); //访问根结点
InOrderTraverse(T->rchild); //递归遍历右子树
}
}
算法5.1 中序遍历的递归算法
void InOrder(BiTree T){
if(T){
InOrder(T->lchild);
cout<<T->data<<" ";
InOrder(T->rchild);
}
}
算法5.2 中序遍历的非递归算法
void InOrder(BiTree T){
//还是模拟上面的遍历过程
BiTree ptr[20];
int top = -1;
/*下面的双重判断和前面的一样,在进栈、出栈的过程中可能会出现栈空的情况,而此时的遍历还没有结束,
所以需要据此来维持循环的进行。*/
while(T || top!=-1){
while(T){
ptr[++top] = T;
T = T->lchild;
}
if(top!=-1){
T = ptr[top--];
cout<<T->data<<" "; //输出在出栈后
T = T->rchild;
}
}
}
1.3.后序遍历
若二叉树为空,则:空操作
否则:
后序遍历左子树(L);
后序遍历右子树(R);
访问根结点(D);
void PostOrderTraverse(BiTree T)
{
if (T) //非空二叉树
{
PostOrderTraverse(T->lchild); //递归遍历左子树
PostOrderTraverse(T->rchild); //递归遍历右子树
printf("%d", T->data); //访问根结点
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下