二叉搜索树是一个链式结构的,快速的进行数据的查询,删除,插入操作的数据结构(lg(n)的时间复杂度)
然而,上面这些所有的功能利用数组+类似快排的操作也能完成,为什么要用跟麻烦的二叉搜索树呢
数组,是一开始就要开好的在内存中占用了一段连续的内存,如果一个程序,他平时的数据流量比较小,用数组的话就必须开到最大流量时的内存
而我们的二叉搜索树是链式存储,并不需要连续的内存,这样就节省了程序运行时的内存消耗
性质:
一个点的所有左子树的值都比这个节点的值小,所有右子树的值都比这个节点的值大
如果有特殊的需求(会出现两个相同的值)我们可以考虑让左子树的值都<=这个节点的值
操作:
插入:
对于如果已有一颗二叉搜索树,我要把值x插入这棵二叉树中
我们只需要从根节点开始比较,如果x < root则往左子树上插否则则往右子树上插
直到我们发现我们要插的子树为空,那么把x放在这里就好了
这个东西用递归实现
查询:
我要在树中查询值为x的节点,我们将x与根节点比较,如果 x < root就在左子树中找否则就在右子树中找
当root == x时root就是要找的节点
删除:
假设要删除x节点
x为叶子节点:直接删掉就好了
x只有左子树或只有右子树:
在网上看这个的时候感觉好多博客都没完全说清楚,我来一个详细的解释
只有左子树:
直接把这个节点删掉,然后把他的左子树(x_left)与原来连接原来连接这个节点的线连接到一起就行了
那么如果原来x是fa_x的右子树,fa_x的右子树就是x_left
因为x下的所有节点都>fa_x 所有x_left做fa_x的右子树是完全没有问题的
是fa_x的左子树同理
只有右子树同理
x既有左子树又有右子树:
这时我们在删掉x后要在右子树中找一个来替换x的位置
要保证x的性质的话,我们只需要找到右子树中最小的(repl_x)那个即可
因为repl_x > x左边所有的数而小于x右边所有的树
把repl_x换过去之后,repl_x就空出来了对吧
因为repl_x是右子树中最小的,那么他肯定没有左子树,这就是删除节点的前两中种情况了,按前两种情况删除repl_x即可
总结:
虽然说二叉搜索树的时间复杂度是(lg(n))但是从操作中可以看出来,我们的时间复杂度实际是O(tree_h)
如果我插入这棵树的时候是按数值顺序插入的,那么这棵树就会退化成一个链表,时间复杂度退化成O(n)
如果有人问,我们已经知道数值了,为什么还要查询这些东西?
那么数值可以理解为主建或者说用户名
跟这个主建所绑定的有其他的东西,比如年龄,学号之类的个人资料,这就是二叉搜索树的实际应用
这也应该是为什么我们要保证玩游戏时用户名不能重复的原因,如果用户名重复。。。。查询个人信息的时候是返回哪个呢?
代码:(下午再写,啦啦啦~)