树
前面我们学习的都是一对一的数据结构,可现实中还存在许多一对多的结构需要处理。这时就需要用到数据结构树了。
树结构广泛存在于现实世界中,公司的组织机构,书的章节等。在计算机应用中,最为人们熟悉的就是磁盘中的文件夹,即文件目录,他包含文件和文件夹。
树是n 个节点的有限集合,当n=0时, 该树为空树,否则,树为非空树。这是一个非空树的概念图(AB…H都是树的节点)。
树和非树
注意:在一个树结构中:每一个节点只能由一个父节点,但是可以由多个孩子节点。
树和非树
有关树的术语
根节点、父节点、子节点
节点也可以称为结点。
一个节点包含了一个数据项以及指向其他节点的分支 。
在数据结构“树”中,第一个节点被称为根节点root
。
-
树是一个非线性的结构
-
树有一个特殊的节点, 称为根节点,和现实中每一棵树有很多根须不同,在数据结构中每一棵树只有一个根节点。
-
树的定义是一个递归的定义,即树的定义中又用到了树的概念。
对于上面这一颗树中,我们可以理解为A树是由B、C两棵树组成。
对于B树,B 节点是该树的根节点,DE分别是他的两个子节点。
度:
节点的度:该节点所拥有的子树棵树。
叶子节点或者终端节点:度为0 的节点就是叶子节点
分支节点或者非终端节点:度不为0 的节点
树的度:整棵树中最大节点的度就是树的度。
层次和高度
从根开始定义,根为第一层,根的子节点为第二层,以此类推。(这个概念没有强制要求,也可以将根节点定义为第0层,这样根节点的子节点就是第一层……)
树的高度:树的高度等于它的最大层数。
祖先和子孙:
节点的祖先和子孙:从根到该节点所经分支的全部节点是该节点的祖先,一个节点的根的子树中所有的节点都是该节点的子孙
注意:在数据结构中,一个节点的祖先节点和子孙节点包括该节点本身。
树结构的表示:
树结构其实是不容易表示出来的,主要原因是因为一棵树中某个节点孩子的数量不确定。
在定义线性表结构的时候,我们知道每一个节点后面最多只会有一个节点,所以我们可以通过数组或者链表中的一对一结构来将多个数据联系起来。
但是在定义树的时候,如果无法确定一个数据项需要对应多少个数据项。所以我们会面临这些问题
1.我们不知道树的度,我们无法确定需要多大的空间来存放子节点的指针。
2.如果我们指定了一棵树的度,那么我们可以利用指针数组来保存数中的各个节点。
#define N 4
struct TreeNode
{
DataType data;
struct TreeNode* sub[N];
}
但是这个方法会存在很大的空间浪费问题:我们需要将每一个节点的度视为最大节点,从而为他们开辟出足够大的空间来存放子节点的指针。
孩子兄弟表示法
在所有用来存储树的结构中,这种结构是最优秀的。
该结构的定义是:
typedef int DataType;
struct TreeNode
{
DataType data; //节点中存储的数据。
struct TreeNode* firstChild; //指向第一个孩子节点
struct TreeNode* pNextBrother; //指向下一个兄弟节点
}
在这个结构中,如果没有子节点,那么firstChild
指针为空指针,
如果后面没有兄弟节点,那么nextBrother
指针为空指针。
下面是其中四个节点(ABDE)的内容,可以方便理解孩子兄弟表示法:
其中A节点中的内容是:
firstChild = pB; //该节点保存第一个子节点的地址。 nextBrother = NULL; //该节点保存下一个兄弟节点的地址。
B节点中的内容:
firstChild = pD; nextBrother = NULL;
D 节点中的内容:
firstChild = NULL; nextBrother = pE;
E 节点中的内容:
> firstChild = NULL; nextBrother = pF;
二叉树:
二叉树就是一颗指明了度为2
的树,即每一个节点最多有两个子节点。
二叉树的逻辑结构
这是一颗典型的二叉树:
对于这颗二叉树每一个根刚好有两个子树,每一棵子树作为根节点时又有两颗子树。
注意:二叉树有一个很重要的性质:二叉树有序的。
简单理解就是:二叉树是分左右子树的,左右子树不能随意颠倒。
二叉树的几种状态:
二叉树的每一个非空节点可以有4种不同的状态:
特殊的二叉树
1.满二叉树
满二叉树是特殊的完全二叉树
满二叉树:每一层的节点都是最大值。
如果一棵树的的层次为k,并且总结点个数为(2^k)-1,那么这棵树就是慢二