一:概述
二叉树(binary tree)是树的一种特殊形式。二叉,顾名思义,这种树的每个节点最多最多有两个孩子节点。注意,这里是最多两个,也可能有一个,或者没有孩子的节点。
二:具体说明
二叉树的结构如下图所示。
二叉树节点的两个孩子节点,一个被称为左孩子(left child),一个被称为右孩子(right child),这两个孩子节点的顺序是固定的,就像是人的左手就是左手,右手就是右手,不能够颠倒或混淆。
此外,二叉树还有两种特殊的形式,一个叫做满二叉树,另一个叫作完全二叉树。
满二叉树:一个二叉树的所有非叶子节点都存在在左右孩子,并且所有的叶子节点都存在同一层级上,呢么这个树就是满二叉树。
简单来说,满二叉树的每一个分支都是满的。
完全二叉树:对于一个右n个结点的二叉树,按层级顺序编号,则所有的节点编号为从1到n。如果这个树的所有节点和同样深度的满二叉树的编号从1到n的节点位置相同,则这个二叉树为完全二叉树。
看了定义也许还不不太清楚,通过完全二叉树图能够更容易理解:
通过上图,二叉树编号从1到12的12个节点,和前面满二叉树编号从1到12的节点位置完全对应。因此这个树是完全二叉树。
完全二叉树的条件没有满二叉树那么苛刻:满二叉树要求所有的分支都是满的,而完全二叉树只需保证最后一个节点之前的节点都齐全即可。
在前面说明栈和队列的博文中,提起到过数据结构分为物理结构和逻辑结构。二叉树属于逻辑结构,它可以通过多种物理结构来表达。
二叉树可以用:
- 链式存储结构
- 数组
来表达。
二叉树是如何使用这两种结构进行存储的。
<1>二叉树最直观的存储方式之链式存储结构
前面博文中说过链表,链表是一对一的存储方式,每一个链表节点拥有data变量和一个指向下一节点的next指针。
而二叉树稍微复杂一些,一个节点最多可以指向左右两个孩子节点,所以二叉树的每一个节点包含三部分。
即:
- 存储数据的data变量
- 指向左孩子的left指针
- 指向右孩子的right指针
<2>下面来看一下利用数组是如何存储的。
使用数组存储时,会按照层级顺序把二叉树的节点放到数组中对应的位置上。如果某一个节点的左孩子或右孩子空缺,则数组的相应位置也空出来。
这样设计的原因是:可以更方便地在数组中定位二叉树的孩子节点和父节点。
假设一个父节点的下标是parent,那么它的左孩子节点下标就是2 x parent + 1,右孩子节点下标就是2 x parent + 2。
反过来,假设一个左孩子节点的下标是leftChild,那么它的父节点下标就是(leftChild - 1) / 2.
假设节点4在数组中的下标是3,节点4是节点,节点4是节点2的左孩子,节点2的下标可以直接通过计算得出。
节点2的下标 = (3 - 1) / 2 = 1
显然易见,对于一个稀疏的二叉树来说,用数组表示法是比较浪费空间的。
最适合数组表示的二叉树-二叉堆,它是一种特殊的完全二叉树,就是用数组来存储的。
三:二叉树的应用
二叉树包含许多特殊的形式,每一种形式都是有自己的作用,但是其最主要的应用还在于进行查找操作和维持相对顺序这两个方面。
<1>查找
二叉树的树形结构使它很适合充当索引。
下面介绍一种特殊的二叉树:二叉查找树(binary search tree).
通过名字可以看出,这种二叉树的主要作用就是进行查找操作。
二叉查找树在二叉树的基础上增加了下面几个条件。
- 如果左子树不为空,则左子树上所有节点的值均小于根节点的值
- 如果右子树不为空,则右子树上所有节点的值均大于根节点的值
- 左、右子树也都是二叉查找树
下面是标准的二叉查找树的图:
二叉查找树的这些条件都是为了方便的查找。
例如查找值为4的节点,步骤如下。
1.访问根节点6,发现4<6.
2.访问节点6的左孩子节点3,发现4>3.
3.访问节点3的右孩子节点4,发现4=4,这正是需要查找的节点。
对于一个节点分布相对均衡的二叉查找树来说,如果节点总数是n,那么搜索节点的时间复杂度就是O(logn),和树的深度是一样的。
这种依靠比较大小来逐步查找的方式,和二分查找算法非常相似。
<2>维持相对顺序
这一点仍然要从二叉查找树说起。二叉查找树要求左子树小于父节点,右子树大于父节点,这样保证了二叉树的有序性。
因此二叉查找树还有另一个名字----二叉排序树( binary sort tree)
新插入的节点,同样需要遵循二叉排序树的原则。例如插入新元素5,由于5<6,所以,5>3,5>4,所以5最中会插入节点4的右孩子位置。
再例如插入一个新元素10,由于10>6,10>8,10>9,所以最终10会插入到节点9的右孩子位置。
这一切虽然看起来很顺利,然而却隐藏着一个致命的问题。如果二叉树中依次插入9,8,6,5,4,会出现下面的结果。
这样不仅看起来很长,而且查询节点的时间复杂度也退化成了O(n).
为了解决这个问题,就要涉及到二叉树的自平衡问题了。二叉树的自平衡方式有很多种,例如红黑树、AVL树、树堆等。这个问题比较复杂,这里就不说明了,要是你有兴趣可以看看下面的链接:
链接:
二叉树的自平衡
除了二叉查找树之外,二叉堆也维持着相对的顺序。不过二叉堆的条件比较宽松一点,只要求父节点比它的左右孩子都大。这个在这里也不赘述了。
写博客不易,希望大家多评论,关注点赞一下。