1、树的定义
我们需要研究这种一对多的数据结构——“树”,考虑它的各种特性,用来解决我们在编程中遇到的各种问题。
树是n个结点的有效集(n>=0)。n=0时称为空树。在任意一颗非空树(1)有且仅有一个特定的称为根(Root)的结点。(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1、T2、......、Tm,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree)
强调两点(1)n>0 时根结点时唯一的,不可能存在多个根结点,数据结构中的树是只能有一个根结点。
(2)m>0 时, 子树的个数没有限制,但它们一定是不相交的。
2、结点分类
1、树的结点包含一个数据元素及若干指向其子树的分支。结点拥有的子树数称为结点的度(Degree)。度为0的结点称为树的叶结点(leaf)或终端结点;度不为0的结点称为非终端结点或分支结点。除根结点之外,分支结点也称为内部结点。树的度是树内各结点的度的最大值。
2、结点间关系
结点的子树的根称为该结点的孩子,相应地该结点称为孩子的双亲节点,同一个双亲的孩子之间互称兄弟。结点的祖先是从根到该结点所经分支上的所有结点。,反之,以某结点为根的子树的任一结点都成为该结点的子孙。
3、树的其他相关概念
结点的层次(level)从根开始定义起,根为第一层,根的孩子在第二层。双亲在同一层的结点互为堂兄弟。树中结点的最大层次称为树的深度(Depth)或高度。如果将树中结点的各子树看成从左至右是有次序的,不能能互换的,则称该树为有序树,否则称为无序树。
森林是m(m>=0)颗互不相交的树的集合。
对比线性表和树的结构,它们有很大的不同:
(1)线性表的第一个元素:无前驱 。最后一个元素:无后继 。中间元素:一个前驱一个后继。
(2)树结构: 根结点:无双亲,唯一 。叶结点:无孩子,可以多个。中间结点:一个双亲多个孩子
3、树的存储结构
简单的顺序存储结构是不能满足树的实现要求的。(谁是谁的双亲,谁是谁的孩子呢?)。不过充分利用顺序顺序存储结构和链式存储结构的特点,完全可以实现对树的存储结构的表示。我们这里要介绍三种不同的表示法:双亲表示法,孩子表示法,孩子兄弟表示法
1、双亲表示法
我们假设以一组连续空间存储空间存储树的结点,该结点由数据域(data域)用于存储数据元素值,指针域(parent)用于存储该结点的双亲结点下标。
#include <stdio.h>
#define MAX_TREE_SIZE 100
typedef int ElemType;
struct _PTNode
{
ElemType data;
int parent;
}PTNode;
树结点的定义如上。下来可以定义树结构,实际上就定义了一个结构体数组,树结构定义如下:
typedef struct _PTree
{
PTNode nodes[MAX_TREE_SIZE]; /*结构体数组*/
int root, n; /*定义根结点,结点数*/
}PTree;
定义根结点(root)的双亲结点下标为-1,即不存在。
这样的存储结构我们可以很容易的找到它的双亲结点,所以时间复杂度为O(1),但是我们如果要知道该结点的孩子结点时什么,这时就需要遍历整个结构才能找到。