API
方法 | 说明 | 运行时间增长数量级 |
---|---|---|
void put(Key key,Value val) | 将键值对存入表中(若值为空则将键key从表中删除) | logN,最坏N |
Value get(Key key) | 获取键key对应的值(若键key不存在则返回null) | logN,最坏N |
void delete(Key key) | 从表中删去键key(及其对应的值) | logN,最坏N |
boolean contains(Key key) | 键key在表中是否有对应的值 | logN |
boolean isEmpty() | 表是否为空 | 1 |
int size() | 表中的键值对数量 | 1 |
Iterable keys() | 表中的所有键的集合 | |
Key min() | 最小的键 | logN,最坏N |
Key max() | 最大的键 | logN,最坏N |
Key floor(Key key) | 小于等于key的键的数量 | logN,最坏N |
Key ceiling(Key key) | 大于等于key的键的数量 | logN,最坏N |
int rank(Key key) | 等于key的键的数量 | logN,最坏N |
Key select(int i) | 排位为i的键 | logN,最坏N |
void deleteMin() | 删除最小的键 | logN,最坏N |
void deleteMax() | 删除最大的键 | logN,最坏N |
int size(Key lo,Key hi) | [lo,hi]之间键的数量 | 1 |
Iterable keys(Key lo,Key hi) | [lo,hi]之间所有的键,已排序 | |
Iterable keys() | 有序表中所有的键,已排序 |
代码主要看put,get,delete,deleteMin,deleteMax,rank,select,floor,ceiling
package xwq.dt;
import xwq.util.StdIn;
import xwq.util.StdOut;
public class BST<Key extends Comparable<Key>, Value> {
private Node root; // 二叉排序树根节点
// 二叉树结点定义
private class Node {
public Key key;
public Value val;
public Node lchild;
public Node rchild;
public int N;// 结点数量,左子树结点数量+右子树结点数量+自身
// 构造函数
public Node(Key key, Value val, int n) {
this.key = key;
this.val = val;
lchild = null;
rchild = null;
N = n;
}
}
public BST() {
root = null;
}
public boolean contains(Key key) {
if (key == null)
throw new NullPointerException();
return get(key) != null;
}
public void put(Key key, Value val) {
if (key == null)
throw new NullPointerException();
if (val == null)
delete(key);
root = put(root, key, val);
}
private Node put(Node root, Key key, Value val) {
// 插入新结点
if (root == null) {
Node newnode = new Node(key, val, 1);
return newnode;
}
// 查找key-value对,插入或更新位置
int cmp = key.compareTo(root.key);
if (cmp == 0)
root.val = val;
else if (cmp < 0)
root.lchild = put(root.lchild, key, val);
else
root.rchild = put(root.rchild, key, val);
// 子结点数量更新
root.N = size(root.lchild) + size(root.rchild) + 1;
return root;
}
public Value get(Key key) {
if (key == null)
throw new NullPointerException();
return get(root, key);
}
private Value get(Node root, Key key) {
if (root == null)
return null;
int cmp = key.compareTo(root.key);
if (cmp == 0)
return root.val;
if (cmp < 0)
return get(root.lchild, key);
else
return get(root.rchild, key);
}
public void delete(Key key) {
if (key == null)
throw new NullPointerException();
if (!contains(key))
return;
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.lchild = delete(x.lchild, key);
else if (cmp > 0)
x.rchild = delete(x.rchild, key);
else {
if (x.lchild == null)
return x.rchild;// 被删除结点只有右子树
if (x.rchild == null)
return x.lchild;// 被删除结点只有左子树
// 右子树最小替换到被删除结点位置
// 1.将指向即将被删除的结点的链接保存为t
// 2.将x指向它的后继结点min(t.right)
// 3.将x的右链接(原本指向一颗所有结点都大于x.key的二叉查找树)指向deleteMin(t.right),
// 也就是再删除后所有结点仍然都大于x.key的二叉查找树
// 4.将x的左链接(本为空)设为t.left(其下所有的key都小于被删除结点和它的后继结点)
Node t = x;
x = min(t.rchild);
x.rchild = deleteMin(t.rchild);
x.lchild = t.lchild;
}
x.N = size(x.lchild) + size(x.rchild) + 1;
return x;
}
private Node deleteMin(Node x) {
if (x == null)
return null;
// 不断深入根节点的左子树,直至遇到一个空链接,然后指向该结点的链接指向该结点的右子树
if (x.lchild == null)
return x.rchild;
x.lchild = deleteMin(x.lchild);
x.N = size(x.lchild) + size(x.rchild) + 1;
return x;
}
private Node deleteMax(Node x) {
if (x == null)
return null;
// 不断深入根节点的右子树,直至遇到一个空链接,然后指向该结点的链接指向该结点的左子树
if (x.rchild == null)
return x.lchild;
x.rchild = deleteMax(x.rchild);
x.N = size(x.lchild) + size(x.rchild) + 1;
return x;
}
// 0到N-1
public int rank(Key key) {
if (key == null)
throw new NullPointerException();
return rank(root, key);
}
// 0到N-1
private int rank(Node root, Key key) {
if (root == null)
return 0;
int cmp = key.compareTo(root.key);
if (cmp < 0)
return rank(root.lchild, key);
else if (cmp > 0)
return size(root.lchild) + 1 + rank(root.rchild, key);
else
return size(root.lchild);
}
// 0到N-1
public Key select(int k) {
if (k < 0 || k >= size())
return null;
return select(root, k);
}
// 0到N-1
public Key select(Node root, int k) {
int i = size(root.lchild);
if (i > k)
return select(root.lchild, k);// 存在于左子树
else if (i < k)
return select(root.rchild, k - i - 1);// 存在于右子树
else
return root.key;
}
public Key floor(Key key) {
if (key == null)
throw new NullPointerException();
return floor(root, key);
}
private Key floor(Node root, Key key) {
if (root == null)
return null;
int cmp = key.compareTo(root.key);
// 存在相同的key
if (cmp == 0)
return root.key;
// 如果待查找key < root.key,到root的左子树继续查找小于等于key的键
if (cmp < 0)
return floor(root.lchild, key);
// 待查找key > root.key
// 如果右子树已空,或右子树最小值大于key,那么root为最大下界结点
Node rmin = min(root.rchild);
if (rmin == null || key.compareTo(rmin.key) < 0)
return root.key;
// 不空,最大下界结点存在于右子树,继续到右子树需找
return floor(root.rchild, key);
}
public Key ceiling(Key key) {
if (key == null)
throw new NullPointerException();
return ceiling(root, key);
}
// 大于等于key的键
private Key ceiling(Node root, Key key) {
if (root == null)
return null;
int cmp = key.compareTo(root.key);
if (cmp == 0)
return root.key;
// key > root.key,到右子树继续寻找符合条件的结点
if (cmp > 0)
return ceiling(root.rchild, key);
// root.key > key,并且root左子树的都小于key,说明root是最小上界结点
Node lmax = max(root.lchild);
if (lmax == null || key.compareTo(lmax.key) > 0)
return root.key;
// 否则上界最小结点存在于左子树中,到左子树中寻找
return ceiling(root.lchild, key);
}
public boolean isEmpty() {
return root == null;
}
public int size() {
return size(root);
}
private int size(Node p) {
if (p == null)
return 0;
return p.N;
}
public Iterable<Key> levelOrder() {
Queue<Key> keys = new Queue<Key>();
if (root == null)
return keys;
// 使用队列做为辅助数据结构实现层次遍历
Queue<Node> q = new Queue<Node>();
q.enqueue(root);
while (!q.isEmpty()) {
Node node = q.dequeue();
keys.enqueue(node.key);
if (node.lchild != null)
q.enqueue(node.lchild);
if (node.rchild != null)
q.enqueue(node.rchild);
}
return keys;
}
public Iterable<Key> keys() {
return keys(min(), max());
}
public Iterable<Key> keys(Key lo, Key hi) {
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 || lo == null || hi == null)
return;
int cmp1 = lo.compareTo(x.key);
int cmp2 = hi.compareTo(x.key);
// 中序遍历
if (cmp1 < 0)
keys(x.lchild, queue, lo, hi);
if (cmp1 <= 0 && cmp2 >= 0)
queue.enqueue(x.key);
if (cmp2 > 0)
keys(x.rchild, queue, lo, hi);
}
public Key min() {
if (isEmpty())
return null;
return min(root).key;
}
private Node min(Node p) {
while (p != null) {
if (p.lchild == null)
return p;
p = p.lchild;
}
return null;
}
public Key max() {
if (isEmpty())
return null;
return max(root).key;
}
private Node max(Node p) {
while (p != null) {
if (p.rchild == null)
return p;
p = p.rchild;
}
return null;
}
public void deleteMin() {
root = deleteMin(root);
}
public void deleteMax() {
root = deleteMax(root);
}
/** * Unit tests the <tt>BST</tt> data type. */
public static void main(String[] args) {
BST<String, Integer> st = new BST<String, Integer>();
for (int i = 0; !StdIn.isEmpty(); i++) {
String key = StdIn.readString();
st.put(key, i);
}
for (String s : st.levelOrder())
StdOut.println(s + " " + st.get(s));
StdOut.println();
for (String s : st.keys())
StdOut.println(s + " " + st.get(s));
StdOut.println();
}
}