参考 算法(第四版)
每个节点的键都大于其左子树中任意节点的键而小于其右子树中任意节点的键。
对于二叉树中任意节点x总是有:
size(x) = size(x.left) + size(x.right) + 1;
(下文)root私有化,所以通过调用公共方法间接调用私有方法。
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;
N = n;
}
}
}
public int size(){
return size(root);
}
private int size(Node x){
if (x == null) return 0;
else return x.N;
}
public Value get(Key key){ // 查找(每次都定义了树的一条路径)
return get(root, key);
}
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);
}
private Node put(Node x, Key key, Value val){
if (x == null) return new Node(key, val ,1); // new
int cmp = key.compareTo(x.key);
if (cmp < 0) x.left = put(x.left, key, val); // insert
else if (cmp > 0) x.right = put(x.right, key, val);
else x.val = val; // update
x.N = size(x.left) + size(x.right) + 1;
return x;
}
public Key min(){ // 左下角最小键值
return min(root).key;
}
private Node min(Node x){
if (x.left == null) return x;
return min(x.left);
}
public Key max(){ // 右下角最大键值
return max(root).key;
}
private Node max(Node x){
if (x.right == null) return x;
return max(x.right);
}
public Key floor(Key key){
Node x =floor(root, key); // 找到对应节点
if (x == null) return null;
return x.key;
}
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 ceil(Key key){
Node x =ceil(root, key); // 找到对应节点
if (x == null) return null;
return x.key;
}
private Node ceil(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.right, key); // 右子树找
Node t = floor(x.left, key); // 左子树找
if (t != null) return t;
else return x;
}
public Key select(int k){ // 排名 -> 键值
return select(root, k).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){ // 键值 -> 排名
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 size(x.left) + 1 + size(x.right);
else return size(x.left);
}
利用好size()
public void deleteMin(){
root = deleteMin(root); // 替换根节点,并更新该子树(其所有节点的键值都大于 x.key )
}
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;
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;
}
public void print(){
print(root);
}
private void print(Node x){ // middle
if (x == null) return;
print(x.left);
System.out.println(x.key);
print(x.right);
}
public Iterable<Key> keys(){ // BST范围查找
return keys(min(), max());
}
public Iterable<Key> keys(Key lo, Key hi){
ArrayList<Key> list = new ArrayList<>();
keys(root, list, lo, hi);
return list;
}
private void keys(Node x, ArrayList<Key> list, 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, list, lo, hi);
if (cmplo <= 0 && cmphi >= 0) list.add(x.key); // 加入list
if (cmphi > 0) keys(x.right, list, lo, hi);
}
keys()的返回数据类型支持foreach迭代即可。
public static void main(String[] args) {
BST<String,Integer> bst = new BST<>();
bst.put("D",4);
bst.put("E",5);
bst.put("F",6);
bst.put("G",7);
bst.put("A",1);
bst.put("B",2);
bst.put("C",3);
Iterable<String> k = bst.keys();
for (String s : k) {
System.out.println(s + " -> "+ bst.get(s));
}
}