文章目录
1 易错概念
- 树中的度不同于图中的度,树中的度指出度(子树数目),而图中的度指总度数(出+入)
- 叶结点是指度数为0的结点,也称为终端结点
- 树的度指树中所有结点度的最大值
2 二叉树的数学性质
- 二叉树的第i层上最多有 2 n − 1 2^{n-1} 2n−1个结点
- 深度为k的二叉树最多有 2 k − 1 2^{k}-1 2k−1个结点
- 对任意一棵二叉树T,叶结点数为
n
0
n_0
n0,度数为2的结点数为
n
1
n_1
n1,则
n
0
=
n
2
+
1.
n_0=n_2+1.
n0=n2+1.
证明: 总 结 点 = n 0 + n 1 + n 2 . 总 边 数 = n 1 + 2 n 2 . 总 结 点 = 总 边 数 + 1 , n 0 + n 1 + n 2 = n 1 + 2 n 2 + 1. 总结点=n_0+n_1+n_2. 总边数=n_1+2n_2.总结点=总边数+1,n_0+n_1+n_2=n_1+2n_2+1. 总结点=n0+n1+n2.总边数=n1+2n2.总结点=总边数+1,n0+n1+n2=n1+2n2+1. - 具有n个结点的完全二叉树深度为:
l
o
g
2
n
+
1.
log_2n+1.
log2n+1.
3 特殊二叉树
- 满二叉树
- 完全二叉树
4 树的存储结构
- 顺序存储结构——空间浪费问题
- 链式存储结构
typedef struct Node{
DataType data;
struct Node *LChild;
struct Node *RChild;
}BiTNode,*BiTree;
一个二叉树有n个结点,则有2n个链域,其中有n+1个空链域(非空链域:n-1 出边数)
5 二叉树的遍历
- 前序遍历
void PreOrder(BiTree root){
if(root!=NULL){
Visit(root->data);
PreOrder(root->LChild);
PreOrder(root->RChild);
}
}
- 中序遍历
void InOrder(BiTree root){
if(root!=NULL){
InOrder(root->LChild);
Visit(root->data);
InOrder(root->RChild);
}
}
- 后序遍历
void PostOrder(BiTree root){
if(root!=NULL){
PostOrder(root->LChild);
PostOrder(root->RChild);
Visit(root->data);
}
}
6 表达式求值
- 前缀表达式 (波兰表达式)
- 中缀表达式 (常用表达式)
- 后缀表达式 (逆波兰)
这三者可以相互转换,比如从中缀表达式到前缀和后缀即是按运算顺序加括号,然后将所有的运算符移动到前面或后面,最后去掉括号的过程。
7 输出二叉树结点
void PrintPreOrder(BiTree root){
if(root!=NULL){
if(root->LChild==NULL&&root->RChild==NULL){
cout<<root->data<<" ";
}
PreOrder(root->LChild);
PreOrder(root->RChild);
}
}
8 统计叶结点数
void leafnum(BiTree root){
if(root!=NULL){
leafnum(root->LChild);
leafnum(root->RChild);
if(root->LChild==NULL&&root->RChild==NULL) leafcnt++;
}
}
分治法:
void leafnum(BiTree root){
int leafcnt;
if(root==NULL) leafcnt=0;
else{
if(root->LChild==NULL&&root->RChild==NULL) leafcnt=1;
else leafcnt=leafnum(root->LChild)+leafnum(root->RChild);
}
return leafcnt;
}
9 树的高度
后序遍历:
从根结点的左右子树开始递归计算,分别算出hl和hr后取较大的加一
int PostTreeDepth(BiTree bt){
int hl,hr,max;
if(bt!=NULL){
hl=PostTreeDepth(bt->LChild);
hr=PostTreeDepth(bt->LChild);
max=hl>hr?hl:hr; //取左右子树深度较大的
return (max+1); //加上根结点
}
}
先序遍历,往下走层次加一,更新深度
void PreTreeDepth(BiTree bt,int h){
//h是当前层次,初始为1
//depth记录最大层次 初始为0
if(bt!=NULL){
if(h>depth) depth=h;
PreTreeDepth(bt->LChild,h+1);
PreTreeDepth(bt->RChild,h+1);
}
}
10 中序遍历的非递归算法
void InOrder(BiTree root){
InitStack(&S);
p=root;
while(p!=NULL||!IsEmpty(S)){
if(p!=NULL){
Push(&S,p);
p=p->LChild;
}else{
Pop(&S,&p);
Visit(p->data);
p=p->RChild;
}
}
}
11 二叉树的线索化
线索化的过程是在遍历过程中修改空指针的过程
12 由遍历序列确定二叉树
参见我的总结:通过遍历结果推二叉树的构造
重重点!
- 前序遍历的第一个元素可以确定根结点
- 后续遍历的最后一个元素可以确定根结点
- 确定了根节点后,通过中序遍历对左右子树进行划分
- 重复上述过程,找根结点并划分左右子树,递归处理,最终得到一棵完整的二叉树
- 另外,一定需要中序才能确定一棵二叉树
13 树 森林与二叉树
树的三种表示方式
- 双亲表示法
- 孩子表示法
- 孩子兄弟表示法 左孩子右兄弟
树 − > -> −> 森林
图中三个步骤即可!
森林 − > -> −> 二叉树
先通过上述方法将树转二叉树,然后下一棵树的根结点作为上一颗树的右孩子组合在一起即可!
二叉树还原为树和森林
树的遍历
- 先根遍历
- 后根遍历
森林的遍历
- 先序遍历
- 中序遍历
- 后序遍历
14 哈夫曼树
带权路径最短二叉树!
选取最小的两个结点组合,在将这两个结点的和加入原序列中,继续选取最小的两个结点,递归组合成为一棵哈夫曼树(直观看,权重大的结点靠近根结点)
15 并查集
16 层次遍历二叉树
本文更新至2020.8.1