引子
继线性表与链表的概念篇与源码剖析篇之后,本来这篇打算剖析一下HashMap,因为每次面试中出现率最高的数据结构就是HashMap。 但是忽然发现, 1.8之前的JDK的HashMap基于数组和链表组合实现,到了1.8之后完全变了,至于它是怎么实现的,这里卖个关子,透漏一下就是跟树有关。因此本篇起开始树系列。
在数据结构中,树和图是两种比较复杂的结构之一;里面涉及各种概念, 各种类型以及不同的算法实现, 希望想学习的小伙伴可以跟着我的节奏,一起克服这些困难。而且重要的是, 树在面试中出现的次数仅次于HashMap, 所以,打起精神来吧!
树
先来说说普通的树
树是由n(n>=1)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
1.每个节点有零个或多个子节点;
2.没有父节点的节点称为根节点;
3.每一个非根节点有且只有一个父节点;
4.除了根节点外,每个子节点可以分为多个不相交的子树;
自然中的树
数据结构中的树
再来看一下百度的解释, 我们发现确实是一颗倒着的树,哈哈!重点看图2,我们总结一下树的特点:
- 有且仅有一个跟节点A(理解为树根),也可以没有(空树)
- 每个节点(根节点除外)只能有一个父节点,可以有多个子节点
- 层次结构A | BC | DE | ####
- 从任意节点来看, 树是一对多的关系
- 树是节点的有穷集(节点数不是无限的)
对照着上图,来看一下,是否符合上面说的特点!看完上面的描述,大体应该对树结构有一个直观的了解了。 那么来科普一下关于树的概念
1.每个元素称为结点(node)
2.节点的度:一个节点含有的子树的个数称为该节点的度;
3.叶节点或终端节点:度为0的节点称为叶节点;
4.非终端节点或分支节点:度不为0的节点;
5.双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;
6.孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;
7.兄弟节点:具有相同父节点的节点互称为兄弟节点;
8.树的度:一棵树中,最大的节点的度称为树的度;
9.节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
10.树的高度或深度:树中节点的最大层次;
11.堂兄弟节点:双亲在同一层的节点互为堂兄弟;
12.节点的祖先:从根到该节点所经分支上的所有节点;
13.子孙:以某节点为根的子树中任一节点都称为该节点的子孙。
14.森林:由m(m>=0)棵互不相交的树的集合称为森林;
以上概念都是根据社会中的家谱与自然中的事物命名的,结合家谱应该很好理解。先给一个简单的树的图,说明一下
- 树的单位是节点, (线性表的单位是什么? 元素; 链表的单位也是节点; 图的单位是顶点)
A-F本身不算节点,A-F所在的小球是节点; 节点包含两个信息: 与其他节点的关系, 节点的值(A, B, C)
- 节点的度
一个节点所包含的子树(子节点)的个数,比如A,B的度都是2(包含两个子节点); C的度是1(仅包含子节点F); D, E, F的度是0(无子节点)
- 根节点与叶节点
把一颗树倒过来就是树结构, 那么A就是树根,称为根节点, 根节点没有父节点, 像树的根。D,E,F就是叶节点, 叶节点没有子节点,像树的叶子。
- 父节点, 子节点, 兄弟节点
关系都是相对的。 A的子节点是B和C, 则B和C的父节点就是A。如果学过DNA,可以根据DNA的图进行关系认定。B和C具有同一个父亲(父节点), 那么B和C必然是兄弟(互为兄弟节点)。
- 堂兄弟节点, 祖先节点
现实中的堂兄弟必然是父辈是亲兄弟。 那么B和C具有相同的父节点,是亲兄弟。 所以B的孩子和C的孩子就是堂兄弟。也即D,E,F互为堂兄弟节点。祖先节点, 一个节点所有的先辈节点,如F的祖先节点,C(父节点), A(祖父节点)。
- 节点的层次
从根节点开始, 每一层的节点的所有子节点算一层。如A是第一层, A的子节点BC是第二层, BC的子节点DEF是第三层,以此类推。
- 树的高度或深度
节点的最大层次,上图树的高度是3; 如果F节点还有一个子节点G, 那么高度就是4。
8.森林
一颗树,只能有一个根节点; 如果一个图中,有N个节点是没有父节点的, 那么整个图就是森林。
树的分类
树
二叉树
满二叉树 与 完全二叉树
二叉查找树(二叉搜索树或二叉排序树)
平衡二叉树(AVL树)
红黑树
二叉树: 每个节点最多只能有两个子节点就是二叉树; 可以没有子节点(叶子节点), 可以只有一个子节点,也可以有两个子节点。上图就是一个二叉树, 它的每个节点最多都只有两个子节点
满二叉树: 我们知道二叉树的每个节点最多只有2个子节点, 那就是它可以允许节点有一个或没有子节点的。比如上图的C节点只有一个右孩子F。 那么满二叉树就是满的二叉树,什么是满的? 除了叶子节点外,每个节点必须都要2个子节点,不允许一个子节点的存在。如果上图C节点添加一个左孩子G , 那么这就是一个满二叉树了。
二叉查找树,或称为二叉搜索树, 二叉排序树: 首先它是一个二叉树,如果不明白二叉树,看上面。其次它要满足一定的条件(如果每个节点的值是一个整数为例):
- 如果它的左子树不为空,那么左孩子的值一定小于根节点的值
- 如果它的右子树不为空,那么右孩子的值一定大于根节点的值
看上面两条其实很好理解, 我们总结一下就是:二叉搜索树的节点的值是有序的; 它总是符合一个规律: 左孩子的值 < 父节点的值 < 右孩子的值。 还是不好理解? 那么上个图看一下
我们可以看到,每个节点的左子树的值,都小于根节点;每个节点的右子树的值,都大于根节点。以根节点12为例, 左子树是5, 2, 9; 右子树是18, 15, 19, 17, 16。 拿出任意节点5, 左孩子节点是2 < 5, 右孩子节点是9 > 5。二叉排序树就是每个节点都符合这标准的二叉树。
在面试或学习中, 二分法是极其常用的,它可以在一定程度上大幅度提高查询效率; 那么对比一下二叉排序树, 是不是发现, 二分法和二叉排序树的思想是一样的?
平衡二叉树,又称AVL树: 首先,它还是一个二叉树。 其次是平衡, 那么平衡的是什么呢? 子树的高度。 它是一颗二叉树, 满足任一节点的左右子树高度差不会大于1。 高度是怎么定义的还有印象吗?
红黑树: 这是一种自平衡二叉树, 后文中会说到。
被动的接受永远是学习的障碍, 接下来布置一个小练习
1. 自己尝试着画一下树的结构,包括二叉树, 二叉排序树, 二叉平衡树,森林等
2. 参考下图,用代码实现一颗树(因为接下来要将递归以及如何遍历二叉树)