参考:《算法第四版》
代码
public class BST<Key extends Comparable<Key>,Value>{
private Node root;//二叉查找树的根节点
private class Node{
private Key key;//键
private Value val;//值
private Node left,right;//指向子树的链接
private int N;//以该节点为根的子树中的节点总数
public Node(Key key,Value val,int N){
this.key=key;
this.val=val;
this.N=N;
}
}
public int size(){
return size(root);
}
public int size(Node x){
if(x==null)
return 0;
else
return x.N;
}
public Value get(Key key){
return get(root,key);
}
//在以x为根节点的子树中查找并返回Key对应的值
//找不到则返回Null
private Value get(Node x,Key key){
if(x==null)
return null;
int cmp=key.compareTo(x.key);
if(cmp<0)
return get(x.left,key);
else if(cmp>0)
return get(x.right,key);
else
return x.val;
}
public void put(Key key,Value val){
root=put(root,key,val);
//查找Key,找到则更新它的值,否则为他创建一个新的节点
}
private Node put(Node x,Key key,Value val){
//如果key存在于以x为根节点的子树中则更新它的值
//否则将以Key和val为键值对的新结点插入到该子树中
if(x==null)
return new Node(key,val,1);//设为根节点,节点总数为1
int cmp=key.compareTo(x.key);
if(cmp<0)
x.left=put(x.left,key,val);
else if(cmp>0)
x.right=put(x.right,key,val);
else
x.val=val;
x.N=size(x.left)+size(x.right)+1;
return x;
}
//最小键
public Key min(){
return min(root).key;
}
public Node min(Node x){
if(x.left==null)
return x;
return min(x.left);
}
//删除最小键
//要不断深入根节点左子树中直至遇见一个空链接
public void deleteMin(){
root=deleteMin(root);
}
private Node deleteMin(Node x){
if(x.left==null)
return x.right;
x.left=deleteMin(x.left);
x.N=size(x.left)+size(x.right)+1;
return x;
}
public void delete(Key key){
root=delete(root,key);
}
private Node delete(Node x,Key key){
if(x==null)
return null;
int cmp=key.compareTo(x.key);
if(cmp<0)
x.left=delete(x.left,key);
else if(cmp>0)
x.right=delete(x.right,key);
else{//这个节点就是要删除的节点
if(x.right==null)
return x.left;//右子树为空,删除了x就只剩左子树,直接返回左子树
if(x.left==null)
return x.right;//左子树为空。。
Node t=x;//要删除的原节点
x=min(t.right);//后继节点
x.right=deleteMin(t.right);//后继节点的右子树=删除了它的 原节点右子树
x.left=t.left;//后继节点的左子树=原节点的左子树
}
x.N=size(x.left)+size(x.right)+1;
return x;
}
}
插入
如果树是空的,就返回一个含有该键值对的新结点。
如果被查找的键小于根节点的键,我们会继续在左子树中插入该键,否则在右子树中插入该键。
删除
怎样删除一个拥有两个子节点的节点?
在删除节点x后用它的后继节点填补它的位置。因为x有一个右子节点,因此它的后继节点就是其右子树中的最小节点。
用4个步骤完成将x替换为它的后继节点的任务:
1.将指向即将被删除的节点的链接保存为t。
2.将x指向它的后继节点min(r.right)
3.将x的右链接(原本指向一颗所有节点都大于x.key的二叉查找树)指向deleteMin(t.right),也就是在删除后所有节点仍然都大于x.key的子二叉查找树。
4.将x的左链接(本为空)设为t.left(其下所有的键都小于被删除的节点和它的后继节点)。