二叉查找树是一个有序的二叉树数据结构。
1.若它的左子树不为空,则左子树上所有结点的值均小于等于根结点的值;
2.若它的右子树不为空,则右子树上所有结点的值均大于等于根结点的值;
3.它的左右子树均为二叉查找树。
简而言之:左节点永远小于等于根节点,根节点永远小于等于右节点,并以此递归。
二叉查找树是有序二叉树,所以当插入、删除节点的时候,都可能会引起排序变化。
如果我们插入节点「3」,因为节点 3 小于节点 10,则在节点 10 的左子树查找。节点 2 小于节点 节点 5, 则在节点 5 的左子树查找。节点 3 大于节点 1,所以需要将节点 1 移动到节点 3 的左子节点,而将节点 3 放置在节点 5 的左子节点。
如果我们要删除节点「5」,那么需要将节点 5 的子节点拿出一个放到节点 5 原来的位置上。由于二叉查找树是有序的,所以需要选择左子树的最大值节点或者右子树的最小值节点,都可以满足要求。
在节点 5 的左子树中,节点 3 为最大节点,我们可以把左子节点 3 与节点 5 交换,并删除节点 5 ,这样二叉查找树仍然是成立的。但是我们在交换节点 3 和节点 5 时发现, 节点 3 仍然有子节点,不能直接删除。所以我们要通过递归的方式,交换节点 1 和 节点 5,最终将节点 5 放在了叶子节点的位置,然后就可以删除了。
如果我们选用右子树的最小值节点 6
然后将节点 5 和 6 进行交换,并删除交换之后的节点 5。
这样,我们就得到了一个没有节点 5 的新的二叉查找树。
有人问了,除了这两种方式,用别的节点行不行?当然是可以的,比如
我们把节点 7 替换节点 5,同时把节点 7 的左子节点 6 挂到节点 3 上。这样也是一个有序的二叉查找树。但是操作更复杂了一些,远不如之前两种方法更简单有效。
插入或者删除节点的原则就是:保证节点是从左到右非递减排列。
为何是非递减?因为可能有相同值的情况发生(比如排序索引相同,但是具体数据不同)
同时还有一个能够直观反映二叉查找树的有序性的方式,二维的二叉查找树结构在一维坐标的投影就是节点的排序。
但是,二叉查找树如果不加以控制,这样会出现一个极端的情况。
可能会出现一个深度很深的二叉查找树,虽然符合二叉查找树的规则,但是如果真的按照二分查找的话,效率会变得十分低下。
二叉查找树的查询复杂度,和二分查找一样,插入和查找的时间复杂度均为 O(logn) ,但是在最坏的情况下仍然会有 O(n) 的时间复杂度。原因在于插入和删除元素的时候,树没有保持平衡。
那么如何解决这个问题呢?就有了下面要介绍的「平衡二叉树」