注:本文没有代码,所有内容均以解决笔试题目为主。当然,读完本文对编写代码和理解树这一概念都会有很大的帮助。
一、概念
1.1 大致结构
图片来源:数据结构:树(Tree)【详解】_数据结构 树_UniqueUnit的博客-优快云博客
1.2 概念
1.有且只有一个根节点。也就是图上的A点。
2.有若干个不相交的子树,这些子树本身也是一棵树。比如以B为根节点的树。
3.每个节点都只有一个父节点但是可以有多个子节点。比如B节点的父节点只有A,但是有E和F两个子节点。
4.根节点没有父节点。
1.3 部分常用术语
深度:从根节点到最底层节点的层数成为深度,根节点是第一层(如上图就是4层)。
叶子节点:没有子节点的节点。即最后一层的结点。
终端节点:度为0的结点,又称叶子节点。
非终端节点:即非叶子节点。
度:子节点的个数为度,树的度取子节点个数最大的那个。
分支结点:度大于0的结点,除了叶子都是分支结点。
内部结点:除了树根和叶子都是内部结点。
二、树的分类
一般树:任意一个节点的子节点的个数都不受限制。
二叉树:任意一个节点的子节点的个数最多两个,且子节点的位置不可更改。二叉树也是我们最常用的,一定要牢牢掌握,后面也会提到很多关于二叉树的性质和作用。如下图,就是一个二叉树。
满二叉树:在不增加树的层数的前提下,无法再多添加一个节点的二叉树就是满二叉树。
完全二叉树:如果只是删除了满二叉树最底层最右边连续若干个节点,这样形成的二叉树就是完全二叉树。
森林:n个互不相交的数树的集合。如下图就是一个简单的森林,由两个树构成。
三、树的性质
下列性质在做考研题的时候常用,而写代码的过程中使用较少。
1.若共有n个节点,总边数为B,则有 B=n-1。
2.深度为k的二叉树至多有2k−1个节点。
3.深度为k且有2k−1个节点的二叉树成为满二叉树。
4.具有n个节点的完全二叉树的深度为log2n+1x表示求不大于x的最大整数。
5.完全二叉树中,对任一个节点i,若 i > 1,则其父节点为 i / 2;若 2i > n,则节点 i 为叶子节点,无左子树;否则,其左子节点为 2i;若 2i + 1 > n,则节点i无右子树;否则,其右子树节点为 2i+1。
注意:若一个二叉树有 n 个节点,则有 n-1 个链域存放指针,有 n+1 个空指针域。
四、树和森林的存储
每一个节点里面分三个部分,一部分存储它的数据,一部分存储左子树的地址,一部分存储右子树的地址,没有左子树或右子树就是NULL(空)。
4.1 双亲表示法
优点:求父节点方便。
如上图的树,存储时结构如表:
数组下标 | 节点(数据) | 父节点 | 原因 |
0 | A | -1 | 由于A没有父节点,所以值为-1 |
1 | B | 0 | B的父节点是A,值为0 |
2 | C | 0 | C的父节点是A,值为0 |
3 | D | 0 | D的父节点是A,值为0 |
4 | E | 3 | E的父节点是D,值为3 |
4.2 孩子表示法
将树中的每个结点的孩子结点排列成一个线性表,用链表存储起来。对于含有 n 个结点的树来说,就会有 n 个单链表,将 n 个单链表的头指针存储在一个线性表中,这样的表示方法就是孩子表示法。
优点:求子节点方便。(图片来源:树的双亲表示法、孩子表示法和孩子兄弟表示法)
如上图所示的树,用孩子表示法表示其节点为:
将头结点 R 的孩子们 A,B,C 排成一个线性表,用链表存储起来。其他的各个结点以此类推,就可以得出图表。
4.3 双亲孩子表示法
使用孩子表示法存储的树结构,正好和双亲表示法相反,适用于查找某结点的孩子结点,不适用于查找其父结点。可以将两种表示方法合二为一,使其求子节点和父节点都方便。
还用上述例题,用双亲孩子表示法来表示其节点:(图片来源:树的双亲表示法、孩子表示法和孩子兄弟表示法)
对比 4.2 和 4.3 可知,双亲孩子表示法在前者的基础上加了一组数据,即父节点的数组下标,这样就就可以很方便的找到父节点。
4.4 二叉链表表示法
作用:把一个普通树转化成二叉树来存储。
做法:设法保证任意一个节点的 左指针域指向它的第一个孩子,右指针域指向它的兄弟 ,只要能满足此条件,就可以把一个普通树转化成二叉树。
还以上图为例,按照上述规则做出它的二叉树为(画的比较丑别介意哈):
4.5 森林的存储
上面前三种方式是树的存储方式,第四种是树和森林转化成二叉树的方式,森林的存储方式为:先把森林转化成二叉树,再存储二叉树。森林的每一个最开始的父节点是兄弟关系。