BST作为符号表的数据结构,很重要的一种。本文将前文中的实现内容汇聚在一起,在经过测试用例测试通过后,可以将实现好版本作为自己的库,以供调用。如果对该api有不同的实现,可以编写不同的实现,如果测试通过,则表明实现正确。
被Client端使用的类型需要经过测试,否则可能扰乱client端代码。
共同构成BST这个类型的一个实现版本。
下面是api
下面是实现:
public class BST<Key extends Comparable<Key>, Value> {
private Node root;
class Node {
private Key key;
private Value value;
private Node left, right;
private int count; // 子树节点个数,算上根
// 节点构造方法
public Node(Key k, Value v, int c) {
key = k;
value = v;
count = c;
}
public Key getKey() {
return key;
}
}
// BST构造方法
public BST() {
root = null;
}
// 插入元素
public void put(Key k, Value v) {
root = put(root, k, v);
}
// 插入子方法.
private Node put(Node x, Key k, Value v) {
if (x == null)
return new Node(k, v, 1);
Node t = new Node(k, v, 1);
// 与当前key相比
int cmp = k.compareTo(x.key);
if (cmp < 0)// 插入到左链接上
x.left = put(x.left, k, v);
else if (cmp > 0) // 插入到右链接上
x.right = put(x.right, k, v);
else
// 更新元素的value
x.value = v;
x.count = size(x.left) + size(x.right) + 1;
return x;
}
// 整个树的大小
public int size() {
return size(root);
}
// 任意一个子树的大小
private int size(Node x) {
if (x == null)
return 0;
else
return size(x.left) + size(x.right) + 1;
}
// 在整棵树中获取key的值
public Value get(Key k) {
return get(root, k);
}
// 指定树下获取key的值
private Value get(Node x, Key k) {
if (x == null)
return null;
// 与当前x的key比较
int cmp = k.compareTo(x.key);
if (cmp < 0)
return get(x.left, k);
else if (cmp > 0)
return get(x.right, k);
else
return x.value;
}
// 在整个树上删除key的节点
/**
*/
public void delete(Key k) {
root = delete(root, k);
}
// 删除以x为根的树中的key的节点,返回该树根,更改型操作要维护count
/***********************
* 0.找到该key 1.没有孩子 2.一个孩子 3.二个孩子 *
*/
private Node delete(Node x, Key k) {
if (x == null)
return null;
int cmp = k.compareTo(x.key);
if (cmp < 0)
x.left = delete(x.left, k);
else if (cmp > 0)
x.right = delete(x.right, k);
else {
// 找到这个key的节点
if (x.left == null)
return x.right;
if (x.right == null)
return x.left;
// 有2个孩子
Node t = x;
x = min(t.right);
x.right = deleteMin(t.right);
x.left = t.left;
}
x.count = 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.count = size(x.left) + size(x.right) + 1;
return null;
}
public Node min() {
return min(root);
}
// 返回以x为根的最小节点
private Node min(Node x) {
if (x == null)
return null;
while (x.left != null)
x = x.left;
return x;
}
// 中序打印,用于验证删除操作
public void print() {
print(root);
}
private void print(Node x) {
if (x == null)
return;
print(x.left);
System.out.println(x.key + " " + x.value);
print(x.right);
}
/********** 与顺序有关的2个api *********/
// 给定key,求排第几
/**
* 3 cases.
* (1) key < x.key。返回在左子树中 的排名
* (2) key > x.key. 先计算右子树排名,加上x左子树个数+1
* (3) key == x.key.返回左子树size()+1
**/
public int rank(Key key) {
return rank(root, key);
}
private int rank(Node x, Key k) {
if (x == null)
return 0;
// 根x比较
int imp = k.compareTo(x.key);
if (imp < 0)
return rank(x.left, k);
if (imp > 0)
return rank(x.right, k) + size(x.left) + 1;
else
return size(x.left) + 1;
}
/**
* 3 cases. r是当前节点排名
* (1) i < r。返回在左子树中 的的第i小的key
* (2) i > r. 返回在右子树中第(i-r)的key
* (3) i == r 返回key
**/
// 返回拍第i的Key
public Key select(int i) {
return select(root, i);
}
private Key select(Node x, int i) {
if (x == null)
return null;
// 根x的排名比较
int r = size(x.left) + 1;
if (i < r)
return select(x.left, i);
if (i > r)
return select(x.right, i - r);
else
return x.key;
}
/***** BST另外2个基于顺序,或者比较操作的api ********/
/****
* public Key floor(Key key) 在整个树中,返回小于等于给定key的最大Key
* public Key ceiling(Key key)在这个树种,返回大于等于给定key的最小key
*
* 这个2个操作思路与rank,select的关系一样,都是以“相反”的操作,所以
* 只要实现一个,另一个就非常easy
*/
public Key floor(Key key) {
return floor(root,key);
}
// 在以x为根的树种,返回"比key小或等的最大数"
/****
* 在实现时,可以这样理解这个操作:"数轴法"
* 在数轴上,比x.key小的数都在左边,比x.key的树都在右边。
* case1: k<x.key 返回floor(x.left,k)
* case2: k>x.key 如果floor(x.right,k)不为空,则返回,否则返回x.key
* case3: k==x.key 返回x.key
*/
private Key floor(Node x, Key k) {
if(x==null) return null;
//开始比较
int cmp = k.compareTo(x.key);
if(cmp<0) return floor(x.left, k);
if(cmp==0) return x.key;
//习惯上把最复杂的放在最后边,而且如果if后面有return,则不需要else
else
{
Key t = floor(x.right,k);
if(t!=null) return t;
else return x.key;
}
}
public Key ceiling(Key key) {
return ceiling(root,key);
}
// 在以x为根的树种,返回"比key大或等的最小数"
/****
* 在实现时,可以这样理解这个操作:"数轴法"
* 在数轴上,比x.key小的数都在左边,比x.key的树都在右边。
* case1: k<x.key 返回 ceiling(x.left,k)不为空,则返回,否则返回x.key
* case2: k>x.key 如果ceiling(x.right,k)
* case3: k==x.key 返回x.key
*/
private Key ceiling(Node x, Key k) {
if(x==null) return null;
//开始比较
int cmp = k.compareTo(x.key);
if(cmp>0) return ceiling(x.right, k);
if(cmp==0) return x.key;
//习惯上把最复杂的放在最后边,而且如果if后面有return,则不需要else
else
{
Key t = ceiling(x.left,k);
if(t!=null) return t;
else return x.key;
}
}
}