二叉查找树(BST)是二叉树, 每个节点的键都大于其左子树的任意节点而小于右子树的任意节点
递归与非递归的实现
递归的实现更容易验证其准确性, 而非递归的实现效率更高。
如果树不是平衡的, 函数调用的栈可能会成为递归的问题。
相关功能的原理与实现
定义类
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 size;
public Node(Key key, Value val, int size) {
this.key = key;
this.val = val;
this.size = size;
}
}
public BST() {
}
... ...
}
查找
一个递归算法,
如果树是空的, 则查找失败;
如果查找的键与树的根节点的键相等, 则返回这个键;
如果查找的键比树的根节点的键大, 则在这个树的右子树寻找;
如果查找的键比树的根节点的键小, 则在这个树的左子树寻找。
private Value get(Key key) {
return get(root, key);
}
private Value get(Node x, Key key) {
if (key == null){
throw new IllegalArgumentException("calls get() with a null 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){
if (key == null){
throw new IllegalArgumentException("calls put() with a null key");
}
if (val == null){
delete(key);
return;
}
root = put(root, key, val);
assert check();
}
private Node put(Node x, Key key, Value val){
if (x == null){
return new Node(key, val, 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.size = 1 + size(x.left) + size(x.right);
return x;
}
删除
如果当前节点的键比查找的键小, 则在它的左子树中删除;
如果当前节点的键比查找的键大, 则在它的右子树中删除;
如果当前节点的键和查找的键相等, 则:
如果它没有左子树, 就用右孩子节点替代这个节点;
如果它没有右子树, 就用左孩子节点替代这个节点;
如果既有左子树, 又有右子树:
用右子树中键最小的节点替代它,
左子树是原来的左子树,
右子树是原来节点的右子树但是删除了最小的节点
(相当于把右子树中最小的节点替换被删除的节点)
public void delete(Key key){
if (key == null) throw new IllegalArgumentException("calls delete() with a null 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;
if(x.left == null)
return x.right;
Node t = x;
x = min(t.right);
x.right = deleteMin(t.right);
x.left = t.left;
}
x.size = size(x.left) + size(x.right) + 1;
return x;
}
private Node deleteMin(Node x){
if (x.left == null){
return x.right;
}
x.left = deleteMin(x.left);
x.size = size(x.left) + size(x.right) + 1;
return x;
}
范围查找
中序遍历。先遍历左子树, 然后检查节点信息, 最后遍历右子树
public Iterable<Key> keys(){
if (isEmpty())
return new Queue<Key>();
return keys(min(), max());
}
public Iterable<Key> keys(Key lo, Key hi){
if (lo == null) throw new IllegalArgumentException("frist argument to keys() is null");
if (hi == null) throw new IllegalArgumentException("second argument to keys is null");
Queue<Key> queue = new Queue<Key>();
keys(root, queue, lo, hi);
return queue;
}
private void keys(Node x, Queue<Key> queue, Key lo, Key hi){
if (x == null) return;;
int cmplo = lo.compareTo(x.key);
int cmphi = hi.compareTo(x.key);
if (cmplo < 0) keys(x.left, queue, lo, hi);
if (cmplo <= 0 && cmphi >= 0) queue.enqueue(x.key);
if (cmphi > 0) keys(x.right, queue, lo, hi);
}
排名
select(int k)获得排名为k的键
rank(Key key)获得key的排名
public Key select(int k){
if (k < 0 || k >= size()){
throw new IllegalArgumentException("argument to select() is invalid: " + k);
}
Node x = select(root, k);
return x.key;
}
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);
else if (t < k)
return select(x.right, k - t - 1);
else
return x;
}
public int rank(Key key){
if (key == null)
throw new IllegalArgumentException("argument to rank() is null");
return rank(key, root);
}
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);
}