数据结构---二叉树
二叉树的性质和存储结构
二叉树的性质
1.在二叉树的第i层上至多有2^i-1个结点(i>=1),最少有1个结点
2.深度为K的二叉树至多有 (2^k)-1 个结点 (k>=1),最少有k个结点
- 将所有层的最大结点数相加
3.对任何一棵二叉树T, 如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1
- 结点总数n=n1+n2+n0
- 除了根结点,其余结点都有和双亲的连接(数目用B表示)可得n=B+1
- 总连接数B=n1+2*n2,可得n=n1+2 *n2+1
- 综上可得n0=n2+1
满二叉树:深度为 K且含有(2^k)-1个结点的二叉树
- 除了根结点和叶子结点外所有结点都有左右两个儿子
- 每一层上的结点数都是最大结点数
完全二叉树:深度为K的, 有n个结点的二叉树, 当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时, 称之为完全二叉树。
这里的对应相当于标号和结点的值都对应
- 叶子结点只可能在层次最大的两层上出现(上一层出现了叶子,那么根据完全二叉树的定义不会出现下一层)
- 对任一结点, 若其右分支下的子孙的最大层次为l, 则其左分支下的子孙的最大层次必为 l 或 l+ 1。
(有右子树一定有对应层次的左子树,有左子树不一定有对应的右子树)
4.--结点和深度的关系
5.
---双亲和左右孩子编号的关系
二叉树的存储结构
顺序存储
#define MAXTSIZE 100//二叉树的最大结点数
typedef TElemType SqBiTree [MAXTSIZE];//定义类型名为SqBiTree来表示二叉树类型,每一个结点类型为TElemType,然后最大结点数为MAXSIZE
SqBiTree bt;
完全二叉树---从根起按层序存储即可,依次自上而下、自左至右存储结点元素,即将完全二叉树上编号为i 的结点元素存储在如 上定义的一维数组中下标为i-1的分量中
一般二叉树---将其每个结点与完全二叉树上的结点相对照,存储在一维数组的相应分量中,不存在该节点编号还是要编的,只是在对应的数组分量中存0
链式存储
typedef struct BiTNode{
TElemType data; //数据域
struct BiTNode *lchild,*rchild;//左右孩子指针,还有可以有一个指向双亲结点的指针
} BiTNode,*BiTree;
对于完全二叉树,用顺序存储比较方便,但是很多一般的二叉树它并不是所有结点都有左右孩子,这就导致用数组来存储时有效存储空间密度很低,所以对于这种采用链式存储
遍历二叉树
按某条搜索路径巡访树中每个结点,使得每个结点均被访问一次,而且仅被访问一次
遍历的路径相当于将二叉树上所有结点都排成一个线性队列
二叉树的基本单元是根结点、左子树和右子树。因此,若能依次遍历(递归)这三部分,便是遍历了整个二叉树。按照先左结点后右结点,有三种遍历情况
若二叉树不为空
先序:访问根结点--->先序遍历左子树--->先序遍历右子树
中序:中序遍历左子树--->访问根结点--->中序遍历右子树
后序:后序遍历左子树--->后序遍历右子树--->访问根结点
中序遍历算法
Status InOrderTraverse(BiTree T)
{
if(T){
InOrderTraverse(T->lchild);
cout<<T->data;
InOrderTraverse(T->rchild);
}
return OK;
}
三种遍历算法区别就在cout<
中序遍历的非递归算法
void InOrderTraverse(Stack* &S, BiTreeNode* &T)//中序遍历二叉树的非递归算法
{
InitStack(S);//初始化栈
BiTreeNode* p=T;//指针p指向根结点
BiTreeNode* q;//申请一个结点q,来存放栈顶弹出的元素
while(p||!StackEmpty(S))
{
if(p)//当p=NULL且栈空时, 循环结束
{
Push(S,p);//根指针进栈
p=p->LChild//遍历左子树
}
else
{
q=Pop(S);//出栈元素指针保存在q中
cout<<q->data;//访问根结点
cout<<" ";
p=q->RChild;//遍历右子树
}
}
}
若结点数为n,每个结点被访问一次,时间复杂度为O(n),栈的最大容量为树的深度,最坏的情况(一个层次一个结点)空间复杂度也为O(n)
根据遍历顺序确定二叉树
后序序列和中序序列均能唯一地确定一棵二叉树
---通过后序序列可以确定根结点,根据中序序列可以确定左右子树
二叉树的先序序列和中序序列也可唯一地确定一棵二叉树
---通过先序序列可以确定根结点,根据中序序列可以确定左右子树
先序遍历的顺序建立二叉链表
void CreateBiTree(BiTree &T)
{
cin>>ch; //输入结点的值
if(ch== '#') T=NULL;//以#结束
else
{
T=new BiTNode; //生成根结点
T-> data=ch; //把ch赋给根结点的数据域
CreateBiTree (T-> lchild); //递归构建左子树
CreateBiTree (T-> rchild);//递归构建右子树
}
}
复制二叉树
void Copy(BiTree T,BiTree &NewT)//复制二叉树T,将复制后的NewT返回
{
if(T==NULL) //若T为空树,复制空树
{
NewT=NULL;
return;
}
else//T不为空树
{
NewT=new BiTNode; //复制根结点
NewT-> data=T->data;
Copy (T-> lchild, NewT-> lchild); //递归复制左子树
Copy (T-> rchild, NewT-> rchild);//递归复制右子树
}
}
计算二叉树的深度
int Depth(BiTree T)
{
if(T==NULL) return 0;
else
{
m=Depth {T->lchild); //递归计算左子树的深度
n=Depth {T->rchild) ; //递归计算右子树的深度
if{m>n) return{m+l);//整个的深度还要加上根节点所占的一层
else return(n+l);
}
}
统计二叉树中结点的个数
int NodeCount(BiTree T)
{
if (T==NULL) return O; //如果是空树,则结点个数为0, 递归结束
else return NodeCount (T->lchild) +Node Count (T->rchild) + 1;//否则返回左右子树的结点之和再加上根节点
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY