树的概念
树的定义
树的形式化定义: T = {D, R} (D表示 数据对象,R 表示数据关系)
D是包含n个节点的有限集合(n≥0)。当n = 0时为空树,否则关系 R 满足以下条件:
① 有且仅有一个节点 d0 ∈ D,它对于关系R来说没有前趋节点,节点d0称作树的根节点。
② 除根节点外每个节点有且仅有一个前趋节点。
③ D中每个节点可以有零个或多个后继节点 。
树的递归定义: 树是由n (n≥0)个节点组成的有限集合(记为T)。其中:
① 如果n = 0, 它是一棵空树,这是树的特例。
② 如果n > 0, 其中存在一个唯一节点作为树的根节点(root),其余节点可分为m(m≥0)个互不相交的有限子集T1、T2 、…、Tm,而每个子集本身又是一棵树 ,称为根节点root的子树。
树中所有节点构成一种层次关系。
树的实际应用
① 红黑树: JAVA8中的hashMap满足一定的阈值,自动扩容时会变为红黑树,treeMap,linux中的epoll模型,nginx中的Timer管理等。
② B,B+树: 广泛用于数据库(mysql,oracle等)的索引。
③ 字典树: 用于海量文本词频统计,查询效率比哈希表还高。
④ 生活中的树状结构有公司职级关系,国家省市区级联,族谱等等都有树结构形式.
树的逻辑表示
(1) 树形表示法: 使用一棵倒置的树表示树结构,非常直观和形象。
(2) 文氏图表示法: 使用集合以及集合的包含关系来描述树结构。
(3) 凹入表示法: 使用线段的伸缩关系描述树结构。
(4) 括号表示法: 用一个字符串表示树。
基本形式: 根(子树1,子树2,…,子树m)
树的基本术语
- 节点的度与树的度:
树中一个节点的子树的个数称为该节点的度。树中各节点的度的最大值称为树的度,通常将度为m的树称为 m次树 或者 m叉树。
- 分支节点与叶节点:
度不为0的节点称为非终端节点,又叫 分支节点。度为0的节点称为终端节点或叶节点(或叶子节点)。
度为1的节点称为 单分支节点;度为2的节点称为双分支节点,依次类推。
- 路径与路径长度:
两个节点di和dj的节点序列(di,di1,di2,…,dj)称为路径。其中<dx,dy>是 分支。
路径长度 等于路径所通过的节点数目减1(即路径上分支数目)。
- 孩子节点、双亲节点和兄弟节点:
在一棵树中。每个节点的后继称作该节点的 孩子节点(或子女节点)。相应地,该节点被称作孩子节点的 双亲节点(或父母节点)。具有同一双亲的孩子节点互为 兄弟节点。
5.子孙节点和祖先节点:
在一棵树中,一个节点的所有子树中的节点称为该节点的 子孙节点。
从根节点到达一个节点的路径上经过的所有节点被称为该节点的祖先节点。
6.节点的层次和树的高度:
树中的每个节点都处在一个层次上。节点的层次从树根开始定义,根节点为第一层,它的孩子节点为第二层,以此类推,一个节点所在的层次为其双亲节点所在层次加1。
树中节点的最大层次称为树的高度(或树的 深度)。
7.有序树和无序树:
若树中各节点的子树是按照一定的次序从左往右安排的,且相对次序是不能随意变换的,则称为 有序树,否则称为 无序树。
8.森林:
n(n>0)个互不相交的树的集合称为 森林。
只要把树的根节点删去就成了森林。反之,只要给n棵独立的树加上一个根节点,并把这n棵树作为该节点的子树,则森林就变成了一棵树。
独木也成林!!!
树的性质
性质1: 树中的节点数等于所有节点的度数+1
① 树中每个分支为一个节点的度 → 所有节点的度之和 = 分支数
② 根节点加上一个分支,这分支数与节点数相同 → 实际分支数 = n-1
其中n=度之和+1。
例题:
性质2: 度为m的树中第i层上至多有m的(i-1)次个节点(i≥1)
度为3的树第二层至多有3个节点 3的(2-1)次 = 3
性质3:
性质4:
树的运算和存储结构
树的基本运算
树的运算主要分为三大类:
查找满足某种特点关系的节点,如查找当前节点的双亲节点等;
插入或删除某个节点,如在树的当前节点上插入一个新节点或者删除当前节点的第i个孩子节点等;
遍历树中每个节点。
树的遍历
树的遍历运算是指按照某种访问方式访问树中的 每一个节点且每一个节点只能被访问一次。
主要的遍历方法:
①先根遍历: 若树不空,则先访问根节点,然后依次先根遍历各棵子树。
② 后根遍历: 若树不空,则依次后根遍历各棵子树,然后访问根节点。
注意:先根和后根遍历算法都是递归的。
③ 层次遍历: 若树不空,则自上而下、自左至右访问树中每个节点。
树的存储结构
1. 双亲存储结构
// 双亲存储结构的类型声明如下
typedef struct
{
ElemType data; //节点的值
int parent; //指向双亲的位置
}PTree[MaxSize];
2. 孩子链存储结构
// 孩子链存储结构的类型声明如下
typedef struct node
{
ElemType data; //节点的值
struct node * sons[MaxSons]; //指向孩子节点
}PSonNode;
其中,MaxSons为最多的孩子节点个数。
3. 孩子兄弟链存储结构
孩子兄弟链存储结构是为每个节点设计3个域:
① 一个数据元素域
② 第一个孩子节点指针域
③ 一个兄弟节点指针域
// 孩子兄弟链存储结构的类型声明如下
typedef struct node
{
ElemType data; //节点的值
struct tnode * hp; //指向兄弟节点
struct tnode * vp; //指向第一个孩子节点
}TSBNode;
每个节点固定只有两个指针域!!!