树
树的概念
树的定义
树形式化定义:T={D,R}。D是包含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的子树。
树的逻辑结构表示
树形表示法:
使用一棵倒置的树表示树结构,非常直观和形象文氏图表示法:
使用集合以及集合的包含关系描述树结构。凹入表示法:
使用线段的伸缩关系描述树结构。括号表示法:
用一个字符串表示树。树的基本术语
节点的度与树的度:树中一个节点的子树的个数称为该节点的度。树中各节点的度的最大值称为树的度,通常将度为m的树称为m次树或者m叉树。
分支节点与叶节点:度不为零的节点称为非终端节点,又叫分支节点。度为零的节点称为终端节点或叶节点(或叶子节点)。
度为1的节点称为单分支节点;度为2的节点称为双分支节点,以此类推
路径与路径长度:两个节点Di和Dj的节点序列(Di,Dj,Di2,....,Dj)称为路径。其中
孩子节点、双亲节点和兄弟节点:在一棵树中,每个节点的后继,被称作该节点的孩子节点(或子女节点)。相应地,该节点被称作孩子节点的双亲节点(或父母节点)
具有同一双亲的孩子节点互为兄弟节点
子孙节点和祖先节点:在一棵树中,一个节点的所以子树中的节点称为该节点的子孙节点。
从根节点到达一个节点的路径上经过的所以节点被称作该节点的祖先节点
节点的层次和树的高度:树中的每一个节点都处在一个层次上。节点的层次从树根开始定义,根节点为第1层,它的孩子节点为第2层,依次类推,一个节点所在的层次为其双亲节点所在的层次加1.
树中节点的最大层次称为树的高度(或树的深度)
有序树和无序树:若树中各节点的子树是按照一定的次序从左向右安排的,且相对次序是不能随意变换的,则称为有序树否则称为无序树
森林:n(n>=0)个互不相交的树的集合称为森林。
只要把树的根节点删去就成了森林
反之,只要给n颗独立的树加上一个节点,并把者n棵树作为该节点的子树,则森林就变成了一棵树
树的性质
性质1:树中的节点数等于所以节点的度数加1.
树中每个分支计为一个节点的度=》所有节点的度之和=分支数
根节点加上一个分支,这样分支数与节点数相同=》实际分支数=n-1
n=度之和+1
性质2:度为m的树中第i层至多有m的(i-1次幂)个节点(i》=1)
性质3:
性质4:具有n个节点的m次树的最小高度为:
树的基本运算
树的运算主要分为三大类:
查找满足某种特定关系的节点,如查找当前节点的双亲节点等;
插入或删除某个节点,如在树的当前节点上插入一个新节点或删除当前节点的第i个孩子节点等;
遍历树中每个节点。
树的遍历
树的遍历运算是指按某种方式访问树中的每一个节点且每一个节点只被访问一次。
主要遍历方法
先根遍历:
若树不空,则先访问根节点,然后依次先根遍历各棵子树。后根遍历:
若树不空,则先依次后根遍历各棵子树然后访问根节点。层次遍历:
若树不空,则自上而下、自左至右访问树中每个节点。
先根遍历和后根遍历是递归的
先根遍历示例的演示
先从根节点开始依次从左往右遍历各棵树
后根遍历示例的演示
先遍历第一棵子树从左叶子节点开始依次访问,遍历完第一棵子树再遍历第2棵子树,依次遍历完再访问根节点
层次遍历示例的演示
从根节点开始从上到下从左往右依次遍历
树的存储结构
双亲存储结构
增加一个伪指针指示其双亲节点的位置,树中任何节点只有唯一的双亲节点
双亲存储结构的类型声明如下:
typedef struct
{
ElemType data; //节点的值
int parent; //指向双亲的位置
} PTree[MaxSize];
孩子链存储结构
每个指针指向一棵子树
孩子链存储结构的节点类型声明如下:
typedef struct
{
ElemType data; //节点的值
struct node * sons[MaxSons]; //指向孩子节点
} TSonNode;
其中,MaxSons为最多的孩子节点个数。
孩子兄弟链存储结构
孩子兄弟链存储结构是每个节点设计3个域:
- 一个数据元素域
- 第一个孩子节点指针域
- 一个兄弟节点指针域
孩子兄弟链存储结构中节点的类型声明如下:
typedef struct tnode
{
ElemType data; //节点的值
struct tnode *hp; //指向兄弟
struct tnode *vp; //指向孩子节点
}TSBNode;