/**
* 基于二叉查找树的符号表。
* @param <Key>
* @param <Value>
*/
public class BTS <Key extends Comparable<Key>,Value> {
private Node root;
private class Node {
private Key key;
private Value value;
private Node left, right;
private int N;
public Node(Key key, Value value, int n) {
this.key = key;
this.value = value;
this.N = n;
}
}
public int size(){
return size(root);
}
private int size(Node node) {
if (node == null) {
return 0;
} else return node.N;
}
private Value get(Node node,Key key){
if (node==null)return null;
int cmp=key.compareTo(node.key);
if (cmp<0)return get(node.left,key);
else if (cmp>0)return get(node.right,key);
else return node.value;
}
public Value get(Key key){
return get(root,key);
}
//put方法里使用了递归,从上往下不断搜索节点,直到node==null,则递归结束并返回一个新的node,并将这个node赋给当前node的left或者right,最后返回当前node(这个node在下面的put方法中被赋给root)。
private Node put(Node node,Key key,Value value){
if (node==null)return new Node(key,value,1);
int cmp=key.compareTo(node.key);
if (cmp<0)node.left=put(node.left,key,value);
else if (cmp>0)node.right=put(node.right,key,value);
else node.value=value;
//node.N等于左右两个节点数的N值加一(加一是因为要算上该节点自身)
node.N=size(node.right)+size(node.left)+1;
return node;
}
public void put(Key key,Value value){
root=put(root,key,value);
}
//以node x为根节点向下寻找最小的key。
private Node min(Node x){
if (x.left==null)return x;
return min(x.left);
}
public Key min(){
return min(root).key;
}
//以node x为根节点向下寻找key所对应的node。
private Node floor(Node x,Key key){
if (x==null)return null;
int cmp=key.compareTo(x.key);
if (cmp==0)return x;
if (cmp<0)return floor(x.left,key);
Node t=floor(x.right,key);
if (t!=null)return t;
else return x;
}
public Key floor(Key key){
Node x=floor(root,key);
if (x==null)return null;
return x.key;
}
//选出二叉排序树中排名第k个key,两个if判断挺好理解的,不再赘述。
private Node select(Node x,int k){
if (x==null)return null;
int t=size(x.left);
if (t>k)return select(x.left,k);
if (t<k)return select(x.right,k-t-1);
else return x;
}
public Key select(int k){
return select(root,k).key;
}
//返回以node x为节点的子树中小于key的键的数量。else if部分加一是因为小于给定key的元素有左边的诸多节点+当前节点以及右边部分节点,因为当前节点的存在,故需要加一。
private int rank(Key key,Node x){
if (x==null){
return 0;
}
int cmp=key.compareTo(x.key);
if (cmp<0)return rank(key,x.left);
else if (cmp>0)return 1+size(x.left)+rank(key,x.right);
else return size(x.left);
}
public int rank(Key key){
return rank(key,root);
}
//画图可以看出来,下面的delete方法也对deleteMin方法进行了分析
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 deleteMin(){
root=deleteMin(root);
}
//delete方法将某一节点删掉后,用该节点右边的最小节点来替代原有节点的位置(因为右边最小节点小于右边左右节点,而大于左边所有节点)
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);//1处
else if (cmp>0)x.right=delete(x.right,key);
else {
//这段代码就是找到了需要删除的节点,随后向右寻找最小的节点进行替换。
if (x.right == null) return x.left;
if (x.left == null) return x.right;
Node t = x;
x = min(t.right);
/*
S
E X
A R
C H
M
假设要删除的元素是E,则deleteMin(t.right);相当于将H删除,将M和R连接, x.right = deleteMin(t.right);则将H和R连接。
x.left = t.left;相当于将H和A连接。 1处那行代码将S与H相连。
*/
x.right = deleteMin(t.right);
x.left = t.left;
}
x.N=size(x.left)+size(x.right)+1;
return x;
}
public void delete(Key key){
root=delete(root,key);
}
}