《算法》笔记 8 - 二叉查找树

• 二叉查找树
• 查找
• 插入
• 性能
• 有序性相关的操作
• 最大键、最小键
• 向上取整、向下取整
• 选择、排名
• 范围查找
• 删除操作
• 删除最大键、最小键
• 通用删除操作

二叉查找树

查找

public class BST<Key extends Comparable<Key>, Value> {
private Node root;

private class Node {
private Key key;
private Value val;
private Node left, right;
public int size;

public Node(Key key, Value val, int size) {
this.key = key;
this.val = val;
this.size = size;
}
}

public 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.right, key);
} else if (cmp < 0) {
return get(x.left, 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 (key == null)
throw new IllegalArgumentException("calls put() with a null key");
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 = size(x.left) + size(x.right) + 1;
return x;
}

x.left = put(x.left, key, val); 类似这样的代码利用递归的特性简洁地实现了结点的添加。在递归调用时，相当于根据二分查找的逻辑，沿着树的某个分支一直向下查找，如果找到，就终止递归，更新结点的值，如果到了树的最底层也没找到，此时key==null成立，递归也会终止，同时新初始化的结点也已经被挂在x.left或者x.right了。

有序性相关的操作

最大键、最小键

public Key min() {
if (isEmpty())
throw new NoSuchElementException("calls min() with empty symbol table");
return min(root).key;
}

private Node min(Node x) {
if (x.left == null)
return x;
else
return min(x.left);
}

public Key max() {
if (isEmpty())
throw new NoSuchElementException("calls max() with empty symbol table");
return max(root).key;
}

private Node max(Node x) {
if (x.right == null)
return x;
else
return max(x.right);
}

向上取整、向下取整


public Key floor(Key key) {
Node n = floor(root, key);
if (n == null) {
return null;
} else {
return n.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 n = floor(x.right, key);
if (n == null) {
return x;
} else {
return n;
}

}

public Key ceiling(Key key) {
if (n == null) {
return null;
} else {
return n.key;
}
}

private Node ceiling(Node x, Key key) {
if (x == null) {
return null;
}

int cmp = key.compareTo(x.key);
if (cmp == 0)
return x;
if (cmp > 0)
return ceiling(x.right, key);

Node n = ceiling(x.left, key);
if (n == null) {
return x;
} else {
return n;
}

}


选择、排名

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 size(x.left) + rank(key, x.right) + 1;
} else if (cmp < 0) {
return rank(key, x.left);
} else {
return size(x.left);
}
}

范围查找

public 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);
}

删除操作

删除最大键、最小键

public void deleteMin() {
root = deleteMin(root);
}

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 void deleteMax() {
root = deleteMax(root);
}

private Node deleteMax(Node x) {
if (x.right == null)
return x.left;
x.right = deleteMax(x.right);
x.size = size(x.left) + size(x.right) + 1;
return x;
}

通用删除操作

• 将指向即将被删除的结点的链接保存为t;
• 将x指向它的后继结点min(t.right)；
• 将x的右链接（原本指向一颗所有结点都大于x.key的二叉查找树）指向deleteMin(t.right)，也就是在删除后所有结点仍然后大于x.key的子二叉查找树。
• 将x的左链接（原本为空）设为t.left（其下所有的键都小于被删除的结点和它的后继结点）。
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.size = size(x.left) + size(x.right) + 1;
return x;
}
posted @ 2019-10-04 11:10  zhixin9001  阅读(...)  评论(...编辑  收藏