数据结构——二叉树

树是一个非常常见的数据结构,应用非常广泛。

而在树中,二叉树是最为常见的,所以我们以二叉树举例说明。

如下图所示,就是一个二叉树

                                                                      图1

图中 22 即为该二叉树的根节点,18为22的左子节点,26为22的右子节点,依此类推,树的最下面一层15,17,19,21,23,25,27,29为叶子节点。

第一点:在认识二叉树之前,需要先了解几个概念,

(1) 节点:每个二叉树都是由一个个节点组成的,每个节点中又保存了4个数据,分别为父节点地址,自身数据,左子节点地址,右子节点地址,如下所示。

(2)度:每一个节点的子节点数量即为该节点的度,有一个子节点则度为1,有两个子节点则度为2,没有子节点则度为0。

(3)树高:树的总层数即为树的高度,如上图1所示,该树自顶向下一共有四层,所以该树的高度为4。

(4)根节点:树的最顶层节点即为根节点.

(5)左子节点:一个结点的左下方节点。

(6)右子节点:一个节点的右下方节点。

(7)根节点的左子树:如图1所示,根节点左侧的半棵小树即为根节点的左子树。

(8)根节点的右子树:如图1所示,根节点右侧的半棵小树即为根节点的右子树。

第二点:值得一提的是,二叉树之所以叫二叉树,是因为任意节点的度都是小于或等于2的。

如果一棵树的度可以小于等于n,那么该树就叫做n叉树,但最为常见也是最常用的还是二叉树。

二叉树还可以分为普通二叉树和二叉查找树,普通二叉树如下图所示:

普通二叉树,他只是结构上符合二叉树的基本特征,但在数据分布上,没有任何规律,所以实际应用不大。

而二叉搜索树就不一样了,如下图所示:

 二叉查找树,又叫做二叉排序树或二叉搜索树,他有以下几个特点:

(1)每一个节点上最多有两个子节点。

(2)任意节点左子树上的值都小于当前节点。

(3)任意节点右子树上的值都大于当前节点。

二叉查找树再添加结点时,有以下规则,可总结为三句话:小的存左边,大的存右边,一样的不存。

第三点:二叉树的四种遍历方式

二叉树的遍历方式,共有四种,分别为前序遍历,中序遍历,后序遍历,层序遍历。

如下二叉树

前序遍历顺序为:根左右,可以解释为从根节点开始,然后按照当前节点,左子节点,右子节点的顺序遍历。遍历如上二叉树后,得到的序列为 20,18,16,19,23,22,24

中序遍历顺序为:左根右,可以解释为从最左边的子节点开始,然后按照左子节点,当前节点,右子节点的顺序遍历。遍历上述二叉树后,得到的序列为 16,18,19,20,22,23,24

根据遍历后的数据不难看出,中序遍历后得到的结果,是按照从小到大的顺序来获取结果的,这种方式是最为常见,也是最重要的。

后序遍历顺序为:左右根,可以解释为从根节点开始,然后按照左子节点,右子节点,当前节点的顺序遍历。遍历上述二叉树后,得到的序列为 16,19,18,22,24,23,20

层序遍历:层序遍历就很好理解了,他是从根节点那一层开始,自顶向下逐层遍历,便利上述二叉树后,得到的结果为 20,18,23,16,19,22,24

第四点:二叉查找树的弊端

 上述我们也已经说过了二叉搜索树的特点,那么这里我列举以下五个数据,7,10,11,12,13,若要将这5个数据添加到二叉搜索树中,会得到如下二叉树:

这样的话,很明显是不太友好地,此时该树就已经变成了一个链表,若要查询13,则要查询5次,查询效率低,那么有什么办法可以避免这种情况的发生呢?这里就引出了平衡二叉树的概念。

第五点:什么是平衡二叉树?

平衡二叉树其实仍是一个二叉搜索树,只是在二叉搜索树的基础上,加了一条限定条件。

平衡二叉树规定:任意节点的左右子树高度差不能超过1。

这里需要注意三个点,1,是任意节点,2,左右子树,3,高度差不超过1

就拿如下二叉树来说,各位认为这是一个平衡二叉树吗?

答案显而易见,不是的,就拿节点10来讲,节点10的左子树高度为0,而右子树高度为3,相差3,不满足相差1,所以很明显他不是一个平衡二叉树。

再来看下面这个树是平衡二叉树吗?

很明显,也不似,仍以节点10来讲,节点10的左子树高度为0,而右子树高度为3,相差3,不满足相差1,所以很明显他不是一个平衡二叉树。

再看一个,如下图:

 很明显,这是一个平衡二叉树,我想应该不需要在这里证明了吧。

上面那个平衡二叉树有些明显,那下面这个还是吗?各位可以看一看,想清楚了再下结论哦。

 它是的,节点7左右字数高度都为2,节点4和节点10左右子树高度差都为1,所以满足平衡二叉树的特性。因此他是一个平衡二叉树。

 相比到了这里,各位一定有些疑问吧。比如平衡二叉搜索树是如何保持平衡的呢?

那么这里就要引出我们的第六点,平衡二叉树的旋转。

首先要知道,旋转分为左旋和右旋,它的触发机制是当添加一个节点之后,该树不在是一个平衡二叉树时,就会发生旋转。旋转又分为左旋和右旋。这里我都一一举例。

左旋举例:如下平衡二叉树

假如我要再添加一个节点为13,那么添加之后的结果应为

 但这里我们不难看出,此时该二叉树已经不再是一个平衡二叉树了,那么就出现问题了,我们该如何让它继续保持平衡呢?就引出了左旋,其实,在旋转之前,我们是无法判断它应该左旋还是右旋,是需要根据插入的节点所在的位置来进行判断的。

在旋转之前,我们首先确定旋转支点,确定方法就是:从添加的节点开始,不断地往父节点寻找不平衡的点。如上,添加了节点12以后,我们往上找,发现从节点10开始该树不平衡,所以10即为旋转支点,可以看出,10节点的右边比作边多,所以判断需要左旋,旋转一共分为3步

(1)以不平衡的点为支点

(2)把支点左旋降级,变成左子节点

(3)晋升原来的右子节点

旋转过程如下:

经旋转后,得到新的平衡二叉搜索树如下:

 刚才的二叉树教为简单,这里我们换一个稍微复杂一点的:

 假设往如下二叉树中插入节点12,插入之后应为:

 这时我们依旧按照刚才的步骤寻找支点,确定7为旋转支点,

这时旋转过程就与刚才的不太一样了

(1)以不平衡的点为支点

(2)将根节点的右侧往左拉

(3)原先的右子节点变成新的父节点,并把多余的左子节点让出,交给已经降级的根节点作为右子节点

旋转之后得到新的二叉树如下:

 这时该树就已经保持平衡了。

右旋举例:如下平衡二叉树

假设要加入节点1,则会变成如下树

 此时不难发现,该树已经不平衡了,因此要进行旋转,还是和刚才一样,先确定旋转支点,找到旋转支点为4。右旋也分为3步,而且旋转步骤与左旋非常相似

(1)以不平衡的点为支点

(2)把支点右旋降级,变成右子节点

(3)晋升原来的左子节点

旋转后得到新的平衡二叉树如下:

 这个选专业时较为简单的,我们来做一个稍微难一点的。

如下二叉树:

 假设要加入节点1,加入后新的树为

 不难看出,此时树已经不平衡,需要旋转,仍然是先确定旋转支点,找到支点为7

 旋转仍然分为3步:

(1)以不平衡的点为支点

(2)将根节点的左侧往右拉

(3)原先的左子节点变成新的父节点,并把多余的右子节点让出,交给已经降级的根节点作为左子节点

经旋转后,新的平衡二叉树如下所示:

第七点:为第六点的补充,平衡二叉树需要旋转的四种情况

分为如下四种

(1)左左:为当根节点的左子树的左子树右节点插入时,导致二叉树不平衡需要旋转

(2)左右:为当根节点的左子树的右子树右节点插入时,导致二叉树不平衡需要旋转

(3)右右:为当根节点的右子树的右子树右节点插入时,导致二叉树不平衡需要旋转

(4)右左:为当根节点的右子树的左子树右节点插入时,导致二叉树不平衡需要旋转

我们一一来举例讲解:

1. 左左,其实不难看出,左左这种情况,和我上面刚才举例的右旋是一样的,所以这里就不再赘述

2. 左右,如下所示,在如下二叉树中插入节点6

插入节点6之后,新的树为

这就是左右,即在左子树的右子树上添加节点,这是我们再来旋转,找到旋转支点为7,进行一次右旋,旋转后结果如下:

 我们发现,旋转后仍然是一个不平衡的二叉树,无法满足我们的要求,因此,仅仅一次右旋是不行的,这里我们需要在右旋之前,先进行一次左旋,将这个左右的情况,变成左左,左旋得到的树如下所示:

 这时我们再来看,就很好进行判断了吧,在进行一次右旋,就变成了

 这时就满足了我们的要求。

总结:当遇到左右时,要先变成左左的情况,这样就好进行判断,也更好的进行变换。

3.  右右:右右这种情况,和我上面刚才举例的左旋是一样的,可以类比思考一下。

4. 右左:这个和左右有些相似,我还是举例说明一下吧

如下树,假设要插入节点8, 

 插入之后得到的树为

可以看到已经不是平衡二叉树,因此要进行旋转,找到旋转支点为7,进行左旋,得到结果为

仍然不是一个平衡二叉树,所以就要考虑换一种思路,想想刚才的左左,举一反三,我们应该大致能联想到,将右左这种情况换成右右,因该就很好解决了吧,我们来试一下,先以10为节点进行一次右旋,得到结果如下:

 这时我们再进行一次左旋,相比就可以得到正确结果了吧

得到新的平衡二叉树为

以上就是平衡二叉树旋转的全部内容了,如果有哪里不懂的话,可以多看几遍,细细品味,仔细推敲。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值