一些概念
度:
- 结点的度:结点子树个数
- 树的度:所有结点的度的最大值
深度:
- 结点层次:根结点层次为1,其余每层递增
- 树的深度:所有结点层次的最大值
- 树的高度:左右子树高度最大值+1。从叶子结点向上数
二叉树:
- 深度为k的二叉树上至多含有2^(k)-1个结点
- 任意二叉树:n0个叶子结点、n2个度为2的结点,n0=n2+1;
- 满二叉树:含有最大结点数
- 完全二叉树:形式上的满二叉树,但没排满。
完全二叉树结点i双亲、孩子:
- 双亲结点:[i/2]
- 左孩子:2i
- 右孩子:2i+1
路径:
- 结点的路径长度:从根结点到该结点路径上分支数
- 结点的带权路径长度:该结点的路径长度×结点上权
- 树的路径长度:树中每个结点的路径长度和
- 树的带权路径长度:树中所有结点的带权路径长度和
二叉树遍历
先序遍历
根——左——右
//先序遍历递归算法
//其余遍历算法与先序遍历类似,此处不再赘述
void xxbl(BiTree T){
if(T){
printf("%c",T->data);
xxbl(T->lchild);
xxbl(T->rchild);
}
}
非递归算法:借助栈实现。
void PreorderTraverse(BiTree T){
SeqStake s;
s.top=-1;
p=T;
while(p){
while(p){
print("%c",p->data);
if(p->rchild){
if(s.top==MAX-1)exit(0);
else s.data[++s.top]=p->rchild;
p=p->lchild;
}
}
if(s.top!=-1) p=s.data[top--];
}
}
中序遍历(非递归)
利用栈实现,与先序遍历算法类似。
void InorderTraverse(BiTree T){
SesStake s;
s.top=-1;
p=T;
while(p||s.top!=-1){
while(p){
if(s.top==MAX-1) exit(0);
s.data[++s.top]=p;
p=p->lc;
}
if(s.top!=-1){
p=s.data[s.top--];
printf("%c",p->data);
p=p->rc;
}
}
}
后序遍历(非递归)
void postorder(BiTree T){
SeqStake2 s;//带标志位的栈
s.top=-1;
p=T;
do{
while(p!=NULL){
s.data[++s.top].d=p;
s.data[s.top].flag=0;
p=p->lchild;
}
while((s.top>-1)&&(s.data[s.top].flag==1)){
p=s.data[s.top--].d;
printf("%c",p->data);
}
if(s.top>-1){
s.data[s.top].flag=1;
p=s.data[s.top].d;
p=p->rchild;
}
}while(s.top>-1);
}
层次遍历
借助队列这一存储结构,实现对二叉树的层次遍历。
应用
- 后序遍历确定树的高度
- 先序/后序+中序唯一确定一棵二叉树。
- 先、中、后分别对应前缀、中缀、后缀表达式
- 先序遍历建立二叉树
void CreatBiTree(BiTree &T){
scanf("%c",&ch);
if(ch=='#') T=NULL;
else{
T=(BiTNode*)malloc(sizeof(BiTNode));
T->data=ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}
线索二叉树
利用空指针域存放某种遍历下的前趋和后继。
树和森林
- 树的双亲表示法:用数组存放结点的data和双亲位置
- 树的孩子表示法:用链表存储孩子的位置。
- 森林→二叉树:左孩子、右兄弟
- 树的遍历:先根、后根、层次遍历。
- 森林的遍历:先序遍历(从左至右对每一棵树先根遍历)、中序遍历(从左至右对每一棵树后根遍历)
赫夫曼树(最优二叉树)
最优二叉树:树的带权路径长度WPL最小的树。
构造方法:选取结点权值最小和次小的两棵二叉树生成新的二叉树,重复这个过程直至剩余一棵二叉树。
赫夫曼编码:从根结点开始,左子树为0,右子树为1。