二叉树的定义
二叉树的定义
二叉树是一种特殊的树,最多只能有两棵子树,且子树有左右之分,不能颠倒
特殊的二叉树
- 满二叉树
- 一棵高度为h,且含有2h−12^h-12h−1个结点的二叉树称为满二叉树,即树中的每层都含有最多的结点
- 可对满二叉树自上而下,自左向右编号(根结点编号为1)
- 对于编号为i的结点,若有双亲,则其双亲为⌊i/2⌋\lfloor i/2 \rfloor⌊i/2⌋;若有左孩子,则左孩子为2i;若有右孩子,则右孩子为2i+1
- 完全二叉树
- 高度为h、有n个结点的二叉树,当且仅当其每个结点都与高度为h的满二叉树中编号1~n的结点一一对应时,称为完全二叉树
二叉树的性质
- 非空二叉树上的叶子结点数等于度为2的结点数加1
- 非空二叉树第kkk层上至多有2k−12^{k-1}2k−1个结点
- 高度为hhh的二叉树至多有2h−12^h-12h−1个结点
- 具有n个结点的完全二叉树的高度为⌈log2(n+1)⌉\lceil \log_2(n+1) \rceil⌈log2(n+1)⌉或者⌊log2(n)⌋+1\lfloor \log_2(n) \rfloor+1⌊log2(n)⌋+1
二叉树的存储结构
顺序存储结构
- 存储在数组中
- 适合存储完全二叉树或满二叉树
- 编号与完全二叉树对应,可利用数组下标确定结点在二叉树中的位置
链式存储结构
typedef struct BiTNode{
ElemType data;
struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
- 在含有n个结点的二叉链表中,含有n+1个空链域
二叉树的遍历
先序遍历
操作过程
若二叉树为空,则什么也不做,否则:
- 访问根节点
- 先序遍历左子树
- 先序遍历右子树
代码实现(递归)
void PreOrder(BiTree T){
if(T != NULL){
visit(T);
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
代码实现(非递归)
版本一:调用栈相关函数,易理解
void PreOrder1(BiTree T){
InitStack(S);
BiTree p = T;
while(p || !IsEmpty(S)){
if(p){
visit(p);
Push(S, p);
p = p->lchild;
}else{
Pop(S, p);
p = p->rchild;
}
}
}
版本二:无调用
void PreOrder2(BiTree T){
BiTree p;
BiTNode *s_pre[MaxSize];
int top = -1;
if(T != NULL){
p = T;
while(top > -1 || p != NULL){
while(p != NULL){
printf("%d ", p->data);
s_pre[++top] = p;
p = p->lchild;
}
if(top > -1){
p = s_pre[top--];
p = p->rchild;
}
}
}
printf("\n");
}
后序遍历
若二叉树为空,则什么也不做,否则:
- 后序遍历左子树
- 后序遍历右子树
- 访问根节点
操作过程
代码实现(递归)
void PostOrder(BiTree T){
if(T != NULL){
PreOrder(T->lchild);
PreOrder(T->rchild);
visit(T);
}
}
代码实现(非递归)
void PostOrder1(BiTree T){
InitStack(S);
p = T;
r = NULL; // 记录最近访问过的结点
while(p || !IsEmpty(S)){
if(p){
Push(S, p);
p = p->lchild;
}else{
GetTop(S, p);
if(p->rchild && p->rchild != r){ // 若右子树存在且未被访问过
p = p->rchild;
}else{ // 否则,弹出根结点,并访问
Pop(S, p);
visit(p);
r = p;
p = NULL; // 重置p指针
}
}
}
}
中序遍历
操作过程
若二叉树为空,则什么也不做,否则:
- 后序遍历左子树
- 访问根节点
- 后序遍历右子树
代码实现(递归)
void InOrder(BiTree T){
if(T != NULL){
PreOrder(T->lchild);
visit(T);
PreOrder(T->rchild);
}
}
代码实现(非递归)
版本一:调用栈相关函数,易理解
void InOrder1(BiTree T){
InitStack(S);
BiTree p = T;
while(p || !IsEmpty(S)){
if(p){
Push(S, p);
p = p->lchild;
}else{
Pop(S, p);
visit(p);
p = p->rchild;
}
}
}
版本二:无调用
void InOrder2(BiTree T){
BiTree p;
BiTNode *s_in[MaxSize];
int top = -1;
if(T != NULL){
p = T;
while(top>-1 || p != NULL){
while(p != NULL){
s_in[++top] = p;
p = p->lchild;
}
if(top > -1){
p = s_in[top--];
printf("%d ", p->data);
p = p->rchild;
}
}
}
printf("\n");
}
层次遍历
操作过程
若二叉树为空,则什么也不做,否则:
- 根结点入队
- 若队空,则结束遍历,否则重复第3步
- 队列中第一个结点出队,并访问,若其有左孩子,则左孩子入队,若其有有孩子,则右孩子入队,返回第2步
代码实现
void LevelOrder(BiTree T){
InitQueue(Q);
BiTree p;
EnQueue(Q, T);
while(!IsEmpty(Q)){
DeQueue(Q, p);
visit(p);
if(p->lchild != NULL)
EnQueue(Q, p->lchild);
if(p->rchild != NULL)
EnQueue(Q, p->rchild);
}
}