本文包括二分查找树基本插入和查找操作
API:
put(Key key, Value value) 插入一个键-值对
get(Key key) 根据一个键返回对应值,如不存在返回null
min() 返回最小键
max() 返回最大键
ceiling(Key k) 返回大于k的最小键
floor(Key k) 返回小于k的最大键
二分查找树作为递归数据结构。尽管也可以使用循环进行查找,最好使用递归方法进行查找。在这里我们使用递归函数两个基本构成:基线条件,状态转移方程,进行说明
1 put
// put a key-value pair into the tree
public void put (Key key, Value value) {
root = insert(key, value, root);
}
private Node insert(Key key, Value value, Node x) {
if (x == null) {
return new Node(key, value, 1);
}
if (x.key.compareTo(key) > 0) { // smaller, move to the left
x.left = insert(key, value, x.left);
} else if (x.key.compareTo(key) < 0) { // larger, move to the right
x.right = insert(key, value, x.right);
} else {
x.value = value; // key existed, replace it
}
x.count = size(x.left) + size(x.right) + 1;
return x;
}
基线条件:x == null, 该索引处没有对象,因而到达了树底端,插入新元素
状态转移方程:如果要插入的键小于当前位置键,插到当前键左子树里,如果大于当前键插到右子树。如果相等则替换值
注:count值用于遍历操作,目前先不涉及,在后续会讲到
2 get
// find a certain value according to its key
public Value get(Key key) {
Node result = get(key, root);
if (result == null) {
return null;
}
return result.value;
}
private Node get(Key key, Node x) {
if (x == null) { // no this key
return null;
}
if (x.key.compareTo(key) > 0) { // smaller, move to the left
return get(key, x.left);
} else if (x.key.compareTo(key) < 0) { // larger, move to the right
return get(key, x.right);
} else {
return x; // find it
}
}
基线条件:如果找到对应键,返回该节点。如果该节点为null,说明搜索到树底端还未找到,返回null
状态转移方程:如果当前键大于目标键,搜索该节点左子树,如果当前键小于目标键,搜索该节点右子树
3 min max
// find the smallest key
public Key min() {
return min(root).key;
}
private Node min(Node x) {
if (x.left == null) {
return x;
} else {
return min(x.left);
}
}
// find the largest key
public Key max() {
return max(root).key;
}
private Node max(Node x) {
if (x.right == null) {
return x;
} else {
return max(x.right);
}
}
min:
基线条件:如果该节点左子节点为null,说明该节点处于最左端,对应最小值。返回该节点
状态转移方程:如果左子节点存在,移到左子节点
max和min原理相同,只是把左移改为右移
4 floor/ceiling
// find the largest key less or equals k
public Key floor (Key k) {
Node x = floor(root, k);
if (x == null) {
return null;
} else {
return x.key;
}
}
private Node floor(Node x, Key k) {
if (x == null) {
return null;
}
int cmp = k.compareTo(x.key);
if (cmp == 0) { // the same key, return it
return x;
} else if (cmp < 0) {
return floor(x.left, k); // smaller, move to the left
} else { // larger, attempt to move to the right
Node t = floor(x.right, k);
if (t != null) {
return t;
} else {
return x;
}
}
}
// find the smallest key larger or equals k
public Key ceiling (Key k) {
Node x = ceiling(root, k);
if (x == null ) {
return null;
}
return x.key;
}
private Node ceiling(Node x, Key k) {
if (x == null) {
return null;
}
int cmp = k.compareTo(x.key);
if (cmp == 0) { // the exact value
return x;
} else if (cmp > 0) {
return ceiling(x.right, k); // larger, move to the left
} else { // smaller, attempt to move to the right
Node t = ceiling(x.left, k);
if (t != null) {
return t;
} else {
return x;
}
}
}
floor:
基线条件:
如果该节点为null,代表达到树底,返回null。
状态转移方程:
如果该节点键大于k,直接左移
如果该节点键小于k,此节点可能为最大值,但也有可能树上存在该键和k之间一个值。此时对右子节点调用floor,如果可以找到符合条件的值返回该值,如果找不到(返回null),返回当前节点
ceiling与floor同理