《王道》数据结构之树和二叉树(五)
数据结构入门之树和二叉树(五)
- 大纲
- 一、树的概念和性质
- 1.1 树的概念
- 1.1.1 树的定义
- 1.1.2 结点分类与结点间关系
- 1.1.3 树的其他相关概念
- 1.2 (非空)树的性质
- 1.3 树的存储结构
- 1.3.1 双亲表示法(顺序存储)
- 1.3.2 孩子表示法
- 1.3.3 孩子兄弟表示法(树与二叉树的转换)
- 1.4 森林与(二叉)树的转换
- 二、二叉树的概念和性质
- 2.1 二叉树的概念
- 2.1.1 二叉树的定义
- 2.1.2 几个特殊的二叉树
- 2.2 二叉树的性质
- 2.3 二叉树的存储结构
- 2.3.1 二叉树的顺序存储
- 2.3.2 二叉树的链式存储(二叉链表)
- 三、二叉树的遍历及线索二叉树
- 3.1 二叉树的四种遍历
- 3.1.1 二叉树的先序遍历(根-左-右)
- 3.1.2 二叉树的中序遍历(左-根-右)
- 3.1.3 二叉树的后序遍历(左-右-根)
- 3.1.4 二叉树的层次遍历
- 3.1.5 由二叉树的遍历序列确定二叉树
- 3.1.6 二叉树遍历的应用
- 3.2 线索二叉树
- 3.2.1 线索二叉树是什么、为什么
- 3.2.2 线索二叉树怎么做
- 3.2.3 在线索二叉树中找前驱后继
- 四、树和森林的遍历
- 4.1 树的三种遍历
- 4.1.1 树的先序遍历(深度优先遍历)
- 4.1.2 树的后序遍历(深度优先遍历)
- 4.1.3 树的层序遍历(广度优先遍历)
- 4.2 森林的两种遍历
- 4.2.1 森林的先序遍历
- 4.2.2 森林的中序遍历
- 五、二叉排序树BST
- 5.1 二叉排序树的定义
- 5.2 二叉排序树的操作
- 5.2.1 二叉排序树的查找
- 5.2.2 二叉排序树的插入和构造
- 5.2.3 二叉排序树的删除
- 六、平衡二叉树AVL
- 6.1 平衡二叉树的定义
- 6.2 平衡二叉树的插入
- 6.2.1 LL平衡旋转(右单旋转)
- 6.2.2 RR平衡旋转(左单旋转)
- 6.2.3 LR平衡旋转(先左后右双旋转)
- 6.2.4 RL平衡旋转(先右后左双旋转)
- 6.3 查找效率分析
- 七、哈夫曼树(二叉树)
- 7.1 哈夫曼树的定义
- 7.2 哈夫曼树的构造
- 7.3 哈夫曼编码
- 总结
- 代码附录
大纲
一、树的概念和性质
1.1 树的概念
1.1.1 树的定义
树是n(n≥0)个结点的有限集(n=0时为空树)。在任意一棵非空树中:(1)有且仅有一个根结点Root,树下面有很多子树(递归)(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1、T2、…Tn,其中每一个集合本身又是一棵树,称为根结点的子树(SubTree)。
树是一种递归定义的数据结构。除了根结点外,任何一个结点都有且仅有一个前驱。每个结点可以有0个或多个后继
注意1:n>0时根结点是唯一的
注意2:m>0时,子树个数没有限制,但他们一定互不相交
1.1.2 结点分类与结点间关系
1. 结点分类
树的结点包含一个数据元素 及 若干指向其子树的分支
结点分类 | 解释 |
---|---|
根结点 | 有且仅有一个根结点(非空树) |
分支结点(非终端结点) | 有后继的结点 |
叶子结点(终端结点) | 没有后继的结点 |
2. 结点间关系
结点间关系 | 解释 |
---|---|
孩子结点(Child) | 结点的子树的根称为该结点的孩子 |
双亲结点(Parent) | 上述的该结点就是孩子的双亲 |
兄弟结点(Sibling) | 同一个双亲的孩子之间互称兄弟 |
堂兄弟结点 | 其双亲在同一层的结点互为堂兄弟 |
祖先结点 | 结点的祖先是从根结点到该结点 所经分支的所有结点 |
子孙结点 | 以该结点为根的子树中的任一结点都称为 该结点的子孙 |
两结点间的路径 | 路径只能从上往下 |
路径长度 | 经过几条“边”(层次的差值) |
根结点:无双亲,唯一
中间结点:一个双亲多个孩子
叶结点:无孩子,可以多个
1.1.3 树的其他相关概念
术语 | 解释 |
---|---|
结点的层次(深度) | 从上往下数(根结点层次为1) |
结点的高度 | 从下往上数(区别树的高度) |
(结点的)度 | 结点有几个孩子/子树 |
树的度 | 树内各结点的度的最大值 |
树的深度/高度 | 树中结点的最大层次 |
- 有序树和无序树:若将树中结点的各子树看成从左至右有次序的,不能互换,则称为有序树,否则为无序树
- 树和森林 :m(m≥0)棵互不相交的树的集合(对树中每个结点而言,其子树的集合就是森林)
1.2 (非空)树的性质
1. 结点数 = 总度数+1(只有根结点头上没有“天线”)
2. 度为m的树、m叉树的区别
- 树的度:各结点的度的最大值
- m叉树:各结点最多只能m个孩子的树
度为m的树 | m叉树 |
---|---|
任意结点的度≤m(最多m个孩子) | 任意结点的度≤m(最多m个孩子) |
至少有一个结点的度=m(有m个孩子) | 允许所有结点的度都<m |
一定是非空树,至少m+1个结点 | 可以是空树 |
相同点:m叉树第i层至多有mi-1个结点; 度为m的树第i层至多有mi-1个结点;**(每个结点都有m个孩子)
不同点: 高度为h的m叉树至多有 (mh-1/m-1) 个结点(等比数列求和m0+m1+ … +mh-1),至少有h个结点; 高度为h、度为m的树至少有h+m-1个结点
3. 具有n个结点的m叉树的最小高度(即完全m叉树)为 [logm(n(m - 1) + 1)]向上取整 或者 [logmn]向下取整+1
- 法一:和上层比较
- 法二:和下层比较
1.3 树的存储结构
1.3.1 双亲表示法(顺序存储)
顺序存储结点数据, 结点中保存父结点在数组中的下标
(除了根结点外,其余每个结点一定有且仅有一个双亲,我们约定根结点的双亲指针域设置为-1)
增/删/改/查优缺点:
- 新增数据元素,无需按逻辑上的次序存储
- 删除数据元素两种方案:删除数据元素,父结点数组下标置为-1;将数组最下面的结点替换删除的结点
删除的不是叶子结点时,要删除其所有子树的结点
- 查:找父结点方便;找孩子不方便
代码实现:
#define MAX_TREE_SIZE 100 //树中最多结点数
typedef int ElemType; //树结点的数据类型暂定为整型//1.结点结构
typedef struct PTNode
{ElemType data; //结点数据元素int parent; //双亲位置域(数组下标)
}PTNode;//2.树结构
typedef struct
{PTNode nodes[MAX_TREE_SIZE]; //结点数组int n; //结点数int r; //根的位置,可不写(默认为0的位置)
}PTree;
1.3.2 孩子表示法
顺序存储结点数据, 结点中保存孩子链表头指针(顺序+链式存储)
增/删/改/查优缺点:
- 查:找孩子方便;找父结点不方便
代码实现:
#define MAX_TREE_SIZE 100 //树中最多结点数
typedef int ElemType; //树结点的数据类型暂定为整型//1.堂兄弟结构(某一结点的所有孩子组成一个链表)
struct CTNode
{ int child; //孩子结点在数组中的位置struct CTNode *next; //下一个孩子
}//2.结点结构
typedef struct
{ElemType data; //结点数据元素struct CTNode *firstChild; //指针域指向第一个孩子(实际指向所有孩子)
}CTBox;//3.树结构
typedef struct
{CTBox nodes[MAX_TREE_SIZE]; //结点数组int n; //结点数int r; //根的位置
}CTree;
1.3.3 孩子兄弟表示法(树与二叉树的转换)
用二叉链表存储树——左孩子右兄弟
(孩子兄弟表示法存储的树, 从存储视角来看形态上和二叉树类似,所以可以森林和二叉树的转换(1.4节),也可以用二叉树的操作来处理树(第四节))
代码实现:
//1.树的结点结构和树结构
typedef struct CSNode{ElemType data; //数据域struct CSNode *firstchild, *nextsibling; //第一个孩子和右兄弟指针
}CSNode,*CSTree;//...
1.4 森林与(二叉)树的转换
本质就是用二叉链表存储森林(孩子兄弟表示法):先将每棵树用孩子转化成二叉树,然后每棵树的根结点为兄弟关系(森林中各个树的根结点之间视为兄弟关系)
二、二叉树的概念和性质
2.1 二叉树的概念
2.1.1 二叉树的定义
二叉树是n(n≥0)个结点的有限集合:
① n = 0 为空二叉树,n = 1 只有根结点
② n > 0 由一个根结点和两个互不相交的被称为根的左子树和右子树组成。左子树和右子树又分别是一棵二叉树。
特点:①每个结点至多只有两棵子树 ②左右子树不能颠倒(二叉树是有序树)
2.1.2 几个特殊的二叉树
1. 满二叉树:一棵高度为h,且含有2h - 1个结点的二叉树
2. 完全二叉树:当且仅当其每个结点都与高度为h的满二叉树中编号为1~n的结点一一对应(如果某结点只有一个孩子,那么一定是左孩子)
3. 二叉排序树:空二叉树或者是具有如下性质的二叉树:
①左子树上所有结点的关键字均小于根结点的关键字;
②右子树上所有结点的关键字均大于根结点的关键字。
③左子树和右子树又各是一棵二叉排序树。
二叉排序树可用于元素的排序、搜索、插入新的结点
4. 平衡二叉树:树上任一结点的左子树和右子树的深度之差不超过1
平衡二叉树能有更高的搜索效率:往宽处长而不往深处长,搜索更快
2.2 二叉树的性质
- 二叉树第i层最多有2i-1个结点 (m叉树第i层至多有mi-1个结点)
- 高度为h的二叉树至多有 (2h-1) 个结点 (高度为h的m叉树至多有 (mh-1/m-1) 个结点)
- 非空二叉树中度为0、1、2的结点个数分别为n0、n1、n2,则n0 = n2 - 1(叶子结点比二分支结点多一个)
- 具有n个(n > 0)结点的完全二叉树的高度h为[log2(n + 1)]向上取整 或[log2n]向下取整 + 1 (同完全m叉树)
- 对于完全二叉树,可以由的结点数n 推出度为0、1和2的结点个数为n0、n1和n2(完全二叉树最多只会有一个度为1的结点)
2.3 二叉树的存储结构
2.3.1 二叉树的顺序存储
1. 完全二叉树
按照从上至下、从左至右的顺序依次存储完全二叉树中的各结点
结点编号一般从1开始,方便找结点的左孩子/右孩子/双亲等
代码实现:
#define MAX_SIZE 100
typedef int ElemType; //树结点的数据类型,暂定为整型//1.结点结构
struct TreeNode{ElemType value; //结点中的数据元素bool isEmpty; //判断结点是否为空
};//2.树结构
TreeNode T[MAX_SIZE]; //定义一个长度为MAX_SIZE的数组T,按照从上至下、从左至右的顺序依次存储完全二叉树中的各结点//3.初始化时所有空结点标记为空
for(int i = 0; i < MAX_SIZE; i++)
{T[i].isEmpty = true ;
}
常考操作(对于一共n个结点的完全二叉树):
查找 | |
---|---|
《王道》数据结构之树和二叉树(五)相关推荐
最新文章
热门文章 |