二叉查找树
也称为有序二叉树,或者已排序二叉树,是指一根空树或者具有下列性质的二叉树:
- 若任意结点的左子树不空,则左子树上所有结点的值均小于它的根节点的值
- 若任意结点的右子树不空,则右子树上所有结点的值均大于它的根节点的值
- 任意结点的左右子树也分别为二叉查找树
- 没有键值相等的节点
因为一颗由n个结点随机构造的二叉查找树的高度为lgn,所以顺理成章,二叉查找树的一般操作的执行时间为O(lgn)。但二叉查找树若退化成了一颗具有n个结点的线性链后,则这些操作的最坏运行时间为O(n)。
1.查找的递归算法
- 如果树是空的,则查找未命中;
- 如果被查找的键和根结点的键相等,查找命中,否则我们就递归地在适当的子树中查找;
- 如果被查找的键较小选择左子树,较大则选择右子树。
package
cn.chen.tree;
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;
this
.
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
k){
if
(x ==
null
)
return null
;
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.
val
;
}
private
Value
get2(Node x,
Key
k){
while
(x !=
null
){
int
cmp = k.compareTo(x.
key
);
if
(cmp ==
0
)
return
x.
val
;
else if
(cmp <
0
) x = x.
left
;
else
x = x.
right
;
}
return null
;
}
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
);
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.
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
);
}
}
2.删除
在删除结点x后用它的后继结点填补它的位置。因为x有一个右子节点,因此它的后继结点就是其右子树中的最小结点。这样替换仍旧可以保持树的有序性。
- 将指向即将被删除的结点的链接保存为t;
- 将x指向它的后继结点min(t.right);
- 将x的右链接指向deleteMin(t.right);
- 将x的左链接设为t.left。
public void
deleteMin(){
root
= deleteMin(
root
);
}
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
;
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
;
// 将指向即将被删除的结点的链接保存为t;
Node t = x;
// 将x指向它的后继结点min(t.right);
x = min(t.
right
);
// 将x的右链接指向deleteMin(t.right);
x.
right
= deleteMin(t.
right
);
// 将x的左链接设为t.left。
x.
left
= t.
left
;
}
x.
N
= size(x.
left
) + size(x.
right
) +
1
;
return
x;
}