树的基本概念
树的定义
采用递归的方式定义树:树是若干个结点的结合,它由唯一的一个根结点和若干不相交的子树构成,每棵子树又是一棵树。
树的基本术语
结点:元素 + 分支(指针)
结点的度:结点的分支数
二叉树
二叉树的定义
- 每个结点最多只有两棵子树,即二叉树中每个结点的度只能是0,1,2
这就说明二叉树有五种形态:空二叉树 + 只有跟结点的二叉树 + 只有左子树 + 只有右子树 + 左右子树都有 - 满二叉树(除了最后一层的叶子结点之外,其它结点都有左孩子和右孩子) + 完全二叉树(编号与满二叉树相同)
二叉树的主要性质
- 叶结点数 = 双分支结点数 + 1
推导过程:总结点数 = 叶节点n0 + 单分支结点n1 + 双分支结点n2
总分支数= n1 + 2n2
总结点数 = 总分支数 + 1;
即n0 + n1 + n2 - 1 = n1 + 2n2;
n0 = n2 + 1; - 第i层最多有2(i-1)个结点
- 深度为k的二叉树最多有2(k) - 1个结点(等比数列求和)
- 已知某结点的编号可推出其双亲结点编号 + 左孩子编号 + 右孩子编号
- n个结点的完全二叉树深度为:log2(n + 1)
二叉树的存储结构
- 顺序:不是很重要
- 链式
typedef struct BTNode {
int data;
struct BTNode *lchild;
struct BTNode *rchild;
}BTNode;
二叉树的遍历算法
- 先序(pre) + 中序(in) + 后序遍历(post)
(如果要用到三个数据(结点数据 + 左孩子数据 + 右孩子数据),则对树的操作应该选用后序遍历,而且这种遍历方式用得相对多)
void preOrderTraverse(BTNode *p) {
if(p != null) {
visit(p);
preOrderTraverse(p->rchild);
preOrderTraverse(p->rchild);
}
}
- 二叉树遍历的应用
注意三点:选用哪种遍历方式 + 返回值(定义变量接受左右子树的值) + 叶结点与其它结点属性是否一样 + 有返回值的话要定义返回值接收的变量
表达式求值p132 + 求树的高度(return LD RD中大的 + 1)
层次遍历
void level(BTNode *p) {
//①定义和初始化循环队列(循环队列中存储的是BTNode指针)
int rear,front;
BTNode *que[maxSize];
rear = front = 0;
BTNode *q;
//②根节点入队
if(p != null) {
rear = (rear + 1) % maxSize;
que[rear] = p;
//③队列不为空时,循环访问队列(出队 + 入队)
while(rear != front)
{
//先访问结点
front = (front + 1) % maxSize;
q = que[front];
visit(q);
//左右子树入队
if(q ->lchild !=null) {
rear = (rear + 1) % maxSize;
que[rear] = q ->lchild;
}
if(q ->rchild !=null) {
rear = (rear + 1) % maxSize;
que[rear] = q ->rchild;
}
}
}
}
线索二叉树的基本概念和构造
- 线索二叉树的由来:充分利用二叉树中的空指针域,更有效对二叉树进行遍历
- 线索二叉树的定义
typedef struct TBTNode {
char data;
//0表示lchild(rchild)指针,1表示指向结点的直接前驱(后继)
int lflag,rflag;
struct TBTNode *lchild,rchild;
}TBTNode;
(知道先序、中序、后序结点就能知道这些线索索引的指向了)
树和森林
- 树与二叉树的转换:孩子为左结点 + 兄弟为右结点
- 森林与二叉树的转换:将森林中每棵树转换成二叉树 + 将其它二叉树作为上一棵二叉树的右子树
- 树和森林的遍历:先根遍历(转化为二叉树的先序遍历) + 后根遍历(转化为二叉树的中序遍历)
树与二叉树的应用
- 二叉排序树和平衡二叉树(放到查找那一章节讲)
- 郝夫曼树和郝夫曼编码
1、郝夫曼树的概念
①郝夫曼树:带权路径最短的二叉树,又叫最优二叉树
②结点的带权路径长度:根节点到该结点的路径长度 X 该节点的权值
③树的带权路径长度(WPL):所有叶子结点的带全路径长度
找一个例子理解这些概念(P143)
2、郝夫曼树(最优二叉树)的构造方法
构造:选最小的两个结点组合
特点:不唯一 + 但是所构造的郝夫曼树的带权路径长度唯一且最小
3、郝夫曼编码
前缀编码:任意一字符的编码,都不是另一个字符编码的前缀
郝夫曼编码:长度最短的前最编码