一. 概述
树的存储结构应用范围极为广泛,我所了解的,如Linux操作系统的目录结构,DNS域名的存储,多路复用中的epoll利用的红黑树…
那么,什么是树嘞?
这就是一颗树,下面引出一些概念
- 空树
上面的每一个圆圈表示一个结点,用n来表示结点个数,当n等于0是则代表树是空树
- 根节点
当n>0时,树有且仅有一个根节点,如图一所示的A结点
- 结点关系
A是B的双亲结点,B是A的孩子结点,B,C是兄弟,E,F是兄弟
- 树的度
也是树的宽度,即结点的分支树的个数,如图一中A结点的度为3,B结点的度为2;以组成该树各节点中最大的度作为树的度,图一树的度为3,树种度为0的结点称为叶子结点或终端结点,度不为0的结点称为分支结点或非终端结点,除终端结点外的分支结点称为内部结点
- 树的深度
组成该树各结点的最大层次,图中的树深度为4
- 森林
若干颗互不相交的树的集合{T1,T2,T3}
- 有序树
如果将树中结点的各子树看成从左至右是有次序的,不能互换的,则称该树为有序树,否则称为无序树
二. 树的实现
前面学习了顺序存储结构,链式存储结构,树的实现也需要用到二者,只是,对于树来说,又有三种表示法,分别是双亲表示法,双亲孩子表示法,孩子兄弟表示法,下面就通过树的实现来体会这些名字的由来.
2.1 双亲表示法
双亲表示法,即以双亲结点为索引的个关键词的一种存储方式,下面来看利用顺序存储的实现:
我们假设以一组连续空间存储树的结点,同时在每个结点中,即存储了本节点的值,还存储了双亲结点的位置,也就是说结点除了知道“我是谁”,还知道“我的双亲是谁”。
#define MAX_TREE_SIZE 100
typedef int ElemType;
typedef struct PTNode
{
ElemType data; //存储结点的数据
ElemType parent; //存储双亲结点的下标
}PTNode;
typedef struct
{
PTNode nodes[MAX_TREE_SIZE]; //存储结点的数组
int r; //根的位置
int n; //结点个数
}PTree;
来看下面这颗树:
再来看用我们上述方法表示的结果:
需要注意,这里是按照层次遍历来表示的(关于遍历方式后面博客会继续总结)
想象一下,既然是结构体,我们还可以存储更多东西,例如在结点的结构体PTNode中接入孩子结点的位置,加入兄弟结点的位置,只要是便于树的操作,完全可以开放性的设计!
2.2 双亲孩子表示法
结合双亲表示法,利用链式存储,则有下面结构
分析完图六,我们再来看双亲孩子表示法的实现:
#define MAX_TREE_SIZE 100
typedef char ElemType;
typedef struct CTNode
{
int child; //孩子结点的下标
struct CTNode *next; //指向孩子的指针
}*ChildPtr;
typedef struct ctbox
{
ElemType data; //结点数据
int parent; //结点下标
ChildPtr firstchild; //指向第一个孩子的指针
}CTBox;
typedef struct pcTree
{
CTBox nodes[MAX_TREE_SIZE];
int r;
int n;
}PCTree;
关于树的其他知识,后续继续总结!