定义
满足下列性质的二叉树(可以是空树)就是二叉搜索树:
- 每一个节点都有一个key值,并且不同节点的key值不一样
- root节点的左子树的所有key值都要比root节点的key值小,右子树的所有key值都要比root节点的key值大
- root的左子树、右子树也满足二叉搜索树的性质(递归定义的二叉搜索树)
每一个节点包含一个key值,以及指向左子树和右子树的引用
带索引的二叉搜索树:在二叉搜索树的基础上,对于每一个节点都增加一个leftSize域,用来存放左子树的节点数+1,表示该节点在其子树中的排名
基本代码(Java)
BinaryNode class:
class BinaryNode{
Object key;
BinaryNode left;
BinaryNode right;
BinaryNode(Object key,BinaryNode left,BinaryNode right){
this.key=key;
this.left=left;
this.right=right;
}
}
BinarySearchTree skeleton:
public class BinarySearchTree{
private BinaryNode root;
public BinarySearchTree(){
root=null;
}
//下面的这些方法参数都不带递归所需要用到的BinaryNode参数
//是因为这是提供给外部的public方法
//实际上需要在这个public方法里面调用private方法,这个private方法里面则需要用到root来开启递归
public boolean isEmpty(){
return root==null;
}
public BinaryNode find(Object key){
//给定一个key值,返回其所在的BinaryNode
}
public BinaryNode findMin(){
//查找最小key
}
public BinaryNode findMax(){
//查找最大key
}
public void insert(Object key){
//插入一个新节点
}
public void remove(Object key){
//删除一个节点
}
public void printTree(){
//打印
}
部分方法的具体实现
private BinaryNode find(Object x,BinaryNode t){
//给定一个key值,返回其所在的BinaryNode
//递归调用自己;外部调用时,传进来的参数t为root
if(t==null)
return null;
if(x.compareTo(t.key)<0)
return find(x,t.left);
else if(x.compareTo(t.key)>0)
return find(x,t.right);
else
return t;
}
private BinaryNode findMin(BinarNode t){
//查找最小key,最大key也是同理
//从t节点开始找
//递归法,迭代也是同理
if(t.left!=null)
return findMin(t.left)
else
return t;
}
private void insert(Object x,BinaryNode t){
//插入一个新节点
//默认插入的key在原来的二叉树里不存在,从root开始比较插
if(t==null)
t=new BinaryNode(x,null,null);
else if(x.compareTo(t.key)<0)
t.left=insert(x,t.left);
else
t.right=insert(x,t.right);
return t;
}
对于删除节点而言,仍要保持二叉搜索树的性质。删除的节点P有三种情况
- P是一个叶节点
- P有一个非空子树
- P有两个非空子树
如图
最简单的情况就是删除叶节点,直接将被删除的节点设为null即可。
对于2、3种情况,我们可以把要被删除的节点的key值用左子树的最大值/右子树的最小值替代,然后删除这个左子树的最大值/右子树的最小值(然后就是递归删除剩下的子树)
删除有两个子树的节点
private BinaryNode delete(Object x,BinaryNode t){
//t最开始是root节点
if(t==null)
return t;
if(x.compareTo(t.key)<0)
t.left=delete(x,t.left);
else if(x.compareTo(t.key)>0)
t.right=delete(x,t.right);
//到这一步时,节点t就是我们要删除的值为x的节点
//前面的部分是在二叉搜索树中找到我们需要删除的那个节点
else if(t.left!=null && t.right!=null){
t.key=findMin(t.right).key;
t.right=delete(t.key,t.right);
}
else
t=(t.left!=null)?t.left:t.right;
}
复杂度分析
- 当这棵二叉搜索树的高度较高接近一颗链表时,那么时间复杂度就比较高,为O(N)
- 对于理想情况下的二叉搜索树,复杂度为O(log2N)