树的基本概念
定义
树是由n(n≥0)个结点(或元素)组成的有限集合(记为T)。
如果n=0,它是一颗空树,这是树的特例;
如果n>0,这n个结点中有且仅有一个结点作为树的根结点,简称为根,其余结点可分为m(m≥0)个互不相交的有限集T1,T2,T3……Tm,其中每个子集本身又是一棵符合本定义的数,称为根节点的子树。
逻辑表示方法
- 树形表示法
- 文式图表示法
- 凹入表示法
- 括号表示法
基本术语
-
结点的度与树的度:树中某个结点的子树的个数称为该结点的度,树中所有结点的度中最大值称为树的度。通常将度为m的树称为m次树
-
分支结点与叶子结点:树中度不为0的结点称为非终端结点,又称分支结点。度为0的结点称为叶子结点。在分支结点中,每个结点的分支数就是该结点的度。如对于度为1的结点,其分支数为1,被称为单分支结点;对于度为2的结点,称为双分支结点。
-
路径与路径长度:对于树中任意两个结点ki,kj,若树中存在一个结点序列,使得序列中除ki以外的任一结点都是其在序列中的前一个结点的后继结点,则称该结点序列为由ki到kj的一条路径。路径长度是该路径所通过的结点数目减1(即路径上分支数目)
-
孩子结点,双亲结点和兄弟结点:在一棵树中,每个结点的后继结点被称为该结点的孩子结点。相应地,该结点被称为孩子结点的双亲结点。具有相同双亲结点的孩子结点互为兄弟结点。进一步推广这些关系,可以把每个结点对应子树中的所有结点(除自身外)称为该结点的子孙结点,把从根结点到达某个结点路径上所经过的所有结点(除自身外)称为该结点的祖先结点。
-
结点层次和树的高度:结点层次或结点深度是从树根开始定义的,根结点为第一层,他的孩子结点为第二层。树中结点的最大层次称为树的高度或树的深度。
-
有序树和无序树:若树中个结点的子树是按照一定的次序从左向右安排的,且相对次序是不能随意变换的,则称为有序树,否则称为无序树。
-
森林:n(n>0)个互不相交的树的集合称为森林。把含有多棵子树的树的根节点删去就成为了森林。
性质
-
树中的结点数等于所有结点的度数之和加1.
-
度为m的树中第i层上最多又mi-1个结点(i≥1)
-
高度为n的m次树最多有(mⁿ-1)/(m-1)个结点
-
具有n个结点的m次树的最小高度为[logm(n(m-1)+1)]
基本运算
- 先根遍历:(1)访问根节点(2)按照从左到右的顺序先根遍历根节点的每一棵子树
- 后根遍历:(1)按照从左到右的顺序先根遍历根节点的每一棵子树(2)访问根节点
- 层次遍历:从根结点开始按从上到下,从左到右的次序访问树中的每一个结点
存储结构
双亲存储结构: 一种顺序存储结构,用一组连续空间存储树的所有结点,同时在每个结点中附设一个伪指针指示其双亲结点的位置
typedef struct{
ElemType data; //存放结点的值
int parent; //存放双亲的位置
} PTree[MaxSize] //PTree为双亲存储结构类型
孩子链存储结构: 每个结点不仅包含结点值,还包括指向所有孩子结点的指针。
typedef struct{
ElemType data; //结点的值
struct node *sons[MaxSons]; //指向孩子结点
} TSonNode; //孩子链存储结构中的结点类型
孩子兄弟链存储结构: 为每个结点设计3个域,即一个数据元素域,一个指向该结点的左边第一个孩子结点(长子)的指针域,一个指向该结点的下一个兄弟结点的指针域。
typedef struct tnode{
ElemType data; //结点的值
struct tnode *hp; //指向兄弟
struct tnode *vp; //指向孩子结点
} TSBNode; //孩子兄弟链存储结构中的结点类型
二叉树的概念和性质
定义
二叉树是一个有限的结点集合,这个集合或者为空,或者由一个根结点和两课互不相交的称为左子树和右子树的二叉树组成。
二叉树与度为2的树差别:
- 度为2的树中至少有一个结点的度为2,而二叉树没有这种要求
- 度为2的树不区分左,右子树,而二叉树是严格区分左,右子树的
满二叉树: 一棵二叉树中所有分支结点都有左孩子结点和右孩子结点,并且叶子结点都集合在二叉树的最下一层。
非空满二叉树:
- 叶子结点都在最下一层
- 只有度为0和度为2的结点
非空完全二叉树:
- 叶子结点只可能在最下面两层中出现
- 对于最大层次中的叶子结点,都依次排列在该层最左边的位置上
- 如果有度为1的结点,只可能出现一个,且该结点只有左孩子而无右孩子
- 按层次编号时,一旦出现编号为i的结点是叶子结点或只有左孩子,则编号大于i的结点均为叶子结点
- 当结点总数n为奇数时,ni=0,当结点总数n为偶数时,n1=1
性质
- 非空二叉树上的叶子结点数等于双分支结点数加1
- 非空二叉树的第i层上最多有2i-1个结点(i≥1)
- 高度为n的二叉树最多有2ⁿ-1个结点(n≥1)
- 具有n个(n>0)结点的完全二叉树的高度为[log₂(n+1)]或[log₂n]+1
二叉树的存储结构
二叉树的顺序存储结构
声明:
typedef ElemType SqBinTree[MaxSize];
二叉树的链式存储结构
声明:
typedef struct node{
ElemType data; //数据元素
struct node *lchild; //指向左孩子结点
struct node *rchild; //指向右孩子结点
} BTNode;
二叉树的基本运算及其实现
二叉树的基本运算概述
- 创建二叉树
- 销毁二叉树
- 查找结点
- 找孩子结点
- 求高度
- 输出二叉树
二叉树的遍历
概念
先序遍历: (1)访问根结点(2)先序遍历左子树(3)先序遍历右子树
中序遍历: (1)中序遍历左子树(2)访问根结点(3)中序遍历右子树
后序遍历: (1)后序遍历右子树(2)后序遍历左子树(3)访问根节点
层次遍历: (1)访问根节点(2)从左到右访问第2层的所有结点(3)从左到右访问第3层的所有结点……第h层的所有结点
层次遍历算法
声明:
typedef struct{
BTNode *data[MaxSize]; //存放队中元素
int front,rear; //队头和队尾指针
}SqQueue; //顺序队类型
哈夫曼树
概述
在n0个带权叶子结点构成的所有二叉树中,带权路径长度WPL最小二叉树称为哈夫曼树或最优二叉树。
构造算法
typedef struct{
char data; //结点值
double weight; //权重
int parent; //双亲结点
int lchild; //左孩子结点
int rchild; //右孩子结点
} HTNode;
哈夫曼编码
设需要编码的字符集合为{d1,d2,……dn0},各个字符在电文中出现的次数集合为{w1,w2……wn0},以d1,d2……dn0作为叶子结点,以w1,w2……wn0作为各根结点到每个叶子结点的权值构造一棵哈夫曼树,规定哈夫曼树的左分支为0,右分支为1,则从根结点到每个叶子结点所经过的分支对应0和1组成的序列便是该结点对应字符的编码,这样的编码称为哈夫曼编码。
typedef struct{
char cd[N]; //存放当前结点的哈夫曼码
int start; //表示cd[start..n0]部分是哈夫曼码
} HCode;