在树中通常将数据元素称为结点。
树是n个结点的有限集合。当n=0时,称为空树,任意一颗非空树满足以及条件:
1:有且仅有一个特定的称为根(root)的结点
2:当n>1时,除根结点之外的其余结点被分成m(m>0)个互不相交的有限集合T1,T2,…,Tn,
其中每个集合又是一棵树,并称为这个根结点的子树。
树的基本术语
结点的度,树的度
某结点所拥有的子树的个数称为该结点的度(degree);树中各结点度的最大值称为该树的度。
叶子结点、分支结点
度为0的结点称为叶子结点(leaf node),也称为终端结点;度不为0的结点称为分支结点(branch node),也称为非终端结点。
孩子结点、双亲结点、兄弟结点
某结点的子树的根结点称为该结点的孩子结点(child node);反之,该结点称为其孩子结点的双亲结点(parent node);具有同一个双亲的孩子结点互称为兄弟结点(brothe)。
路径、路径长度
如果树的结点序列n1,n2,…nk满足如下关系:结点ni是结点n(i+1)的双亲(1≤i<k)则n1n2…nk称为一条由n1至nk的路径(path);路径上经过的边数称为路径长度(h)。显然,在树中路径是唯一的。
祖先、子孙
如果从结点x到结点y有一条路径,那么x就称为y的祖先,y称为x的子孙。显然,以某结点为根的子树中的任一结点都是该结点的子孙。
结点的层数、树的深度(高度)、树的宽度
规定根结点的层数(level)为1,对其余任何结点,某结点在第k层,则其孩子结点在k+1层;树中所有结点的最大层数称为树的深度(depth),也称为树的高度。树中每一层结点个数的最大值称为树的宽度(breadth)。
树的遍历
树的遍历是指从根结点出发,按照某种次序访问树中所有的结点,使得每个结点被访问且只被访问一次。树的遍历次序通常有前序遍历,后序遍历,和层序遍历。
树的前序遍历操作:
若树为空,则空操作返回,否则执行以下操作
1 访问根结点
2 按照从左到右的顺序前序遍历根结点每一颗子树。
树的后序遍历操作:
若树为空,则空操作返回,否则执行以下操作
1 按照从左到右的顺序后序遍历根结点每一颗子树。
2 访问根结点
树的层次遍历操作:
从树的根结点开始,自上而下逐层遍历,在同一层中,按照从左到右的顺序对结点逐个访问。
树的存储结构
一:双亲表示法
template<typename T>
struct Node{
T data;
int parent;
};
存储思路:用一维数组来存储树的各个结点,数据元素包括树中结点的数据信息,以及该结点的双亲在数组中的下标。
二:孩子表示法
孩子表示法是基于链表的存储方法,把每个结点的孩子排列起来,看成一个线性表,且以单链表存储,称为该结点的孩子链表。假设有n个结点,也就有n个孩子链表,也就有n个头指针,这n个头指针又构成了一个线性表,采用顺序存储。将存放n个头指针的数组和存放n个结点信息的数据结合,构成孩子链表的表头数组。
struct CTNode{
int child;//链表中每个结点存储的不是数据本身,而是数据在数组中存储的位置下标
CTNode * next;
}
struct CBNode{
T data;//结点的数据类型
CTNode *firstchild;//孩子链表的头指针
}
三:孩子兄弟表示法
链表中的每个结点除数据域外,还设置了两个指针分别指向该结点的第一个孩子和右兄弟。
typedef struct CSNode{
ElemType data;
struct CSNode * firstchild,*nextsibling;
}
孩子兄弟表示法与单链表的相关算法类似,就不多叙述。