算法初接触 | 数据结构[二叉查找树]

151 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天

二叉查找树

二叉查找树(又叫作二叉搜索树或二叉排序树)是一种数据结构,采用了图的树形结构。数据存储于二叉查找树的各个结点中

图示

01

1.jpg
结点中的数字便是存储的数据。此处以不存在相同数字为前提进行说明

02

2.jpg
二叉查找树有两个性质。第一个是每个结点的值均大于其左子树上任意一个结点的值。比如结点9大于其左子树上的3和8

03

4.jpg
同样,结点15也大于其左子树上任意一个结点的值

04

4.jpg
第二个是每个结点的值均小于其右子树上任意一个结点的值。比如结点15小于其右子树上的23、17和28

05

5.jpg
根据这两个性质可以得到以下结论。首先,二叉查找树的最小结点要从顶端开始,往其左下的末端寻找。此处最小值为3

06

6.jpg
反过来,二叉查找树的最大结点要从顶端开始,往其右下的末端寻找。此处最大值为28

07

7.jpg
试着往二叉查找树添加数据,如添加数字1

08

8.jpg
首先,从二叉查找树的顶端结点开始寻找添加数字的位置。将想要添加的1与该结点中的值进行比较,小于它则往左移,大于它则往右移

09

9.jpg
1<9,故将1左移

10

10.jpg
由于1<3,所以继续将1往左移,但前面已经没有结点了,所以把1作为新结点添加到左下方

11

11.jpg
1的添加操作完成

12

12.jpg
试着添加数字4

13

13.jpg
首先寻找添加数字的位置

14

14.jpg
4<9,左移

15

15.jpg
4>3,右移

16

16.jpg
由于4<8,所以需要将其往左移,但前面已经没有结点了,所以把4作为新结点添加到左下方

17

17.jpg
4的添加操作完成

18

18.jpg
接下来看看如何在二叉查找树中删除结点。比如删除结点28

19

d1bbbd11429396c62b5709e81166cd1.jpg
若需要删除的结点没有子结点,直接删掉该结点即可

20

20.jpg
试着删除结点8

21

21.jpg
如果需要删除的结点只有一个子结点,那么先删掉目标结点

22

22.jpg
然后把子结点移到被删除结点的位置上即可

23

23.jpg
最后试着删除结点9

24

24.jpg
如果需要删除的结点有两个子结点,那么先删掉目标结点

25

25.jpg
然后在被删除结点的左子树中寻找最大结点

26

26.jpg
最后将最大结点移到被删除结点的位置上。这样一来,就能在满足二叉查找树性质的前提下删除结点了。如果需要移动的结点(此处为4)还有子结点,就递归执行前面的操作

27

27.jpg
下面来看如何在二叉树中查找结点,比如试着查找12

28

28.jpg
从二叉查找树的顶端结点开始往下查找。和添加数据时一样,把12和结点中的值进行比较,小于该结点的值则往左移,大于则往右移

提示:删除9的时候,我们将“左子树中的最大结点”移动到了删除结点的位置上,但是根据二叉查找树的性质可知,移动“右子树中的最小结点”也没有问题

29

29.jpg
12>4,右移

30

30.jpg
找到结点12

解说
我们可以把二叉查找树当作是二分查找算法思想的树形结构体现(二分查找的详细说明在3-2节)。因为它具有前面提到的那两个性质,所以在查找数据或寻找适合添加数据的位置时,只要将其和现有的数据比较大小,就可以根据比较结果得知该往哪边移动了。
比较的次数取决于树的高度。所以如果结点数为n,而且树的形状又较为均衡的话,比较大小和移动的次数最多就是log,n。因此,时间复杂度为O(logn)。但是,如果树的形状朝单侧纵向延伸,树就会变得很高,此时时间复杂度也就变成了O(n)。

补充说明
有很多以二叉查找树为基础扩展的数据结构,比如“平衡二叉查找树”。这种数据结构可以修正形状不均衡的树,让其始终保持均衡形态,以提高查找效率。
另外,虽然文中介绍的二叉查找树中一个结点最多有两个子结点,但我们可以把子结点数扩展为m(m为预先设定好的常数)。像这种子结点数可以自由设定,并且形状均衡的树便是B树。