正在学习算法导论,根据书上的伪代码和思想实现二叉查找树。
主要方法有:
1.查找最大关键字的结点
2.查找最小关键字的结点
3.查找特定关键字的结点
4.查找一个结点的后继结点(即按照中序遍历在该点后一个位置的点,这个点的键值是比该点键值大的最近的点)。
5.插入节点
6.删除结点
每个方法的思想:
1.查找最大关键值的点:
根据二叉查找树的性质,关键字最大的点在树的最右边
Entry TreeMaximum(Entry x) {
if (x.right!= null)
x = x.right;
return x;
}
2.同理,关键字最小的点在最左边
Entry TreeMinimum(Entry x) {
if (x.left != null)
x = x.left;
return x;
}
3.查找特定关键字的点
Entry TreeSearch(int key){
Entry x=root;
while(x!=null&&x.key!=key){
if(x.key<key)
x=x.right;
else
x=x.left;
}
//要么x==null,要么x.key=-key,x==null说明没找到
return x;
}
4.查找一个节点的后继结点(即按照中序遍历在该点后一个位置的点,这个点的键值是比该点键值大的最近的点)。:
这里分两种情况,
1)当该节点的右孩子结点不为空时,我们可以确定比该键值大的最接近的节点一定在该节点的右子树上。并且是右子树的最小键值结点。
2)当该节点没有右孩子结点,那么它的后继节点一定是他的祖先,并且该节点处于后继结点的左子树上。那么找到最近的一个祖先结点y,y.left也是该节点的祖先(一个节点可以是自己的祖先)
Entry TreeSuccessor(Entry x) {
if (x.right != null) {
return TreeMinimum(x);
} else {
Entry y = x.p;
while (y != null && x == y.right) {
x = y;
y = y.p;
}
return y;
}
}
5.插入节点,这个比较简单,一直比较找到一个合适的父节点就行了。然后挂在父节点的下面
void TreeInsert(Entry x) {
Entry k = root;
Entry y=null;
while (k != null) {
y=k;
if (x.key < k.key)
k = k.left;
else
k = k.right;
}
if(y!=null)
if(x.key<y.key)
y.left=x;
else
y.right=x;
else
root=x;
x.p=y;
}
6.删除结点,这个比较麻烦,分四种情况:
1)当该节点孤家寡人,没有子节点时,好办!直接把他的父节点的左(右)节点设置为null
2)当该节点只有一个孩子节点时,如果是只有左孩子,那么将该节点的父节点的左(或者右)孩子节点(看本身该节点处于其父节点的左还是右孩子节点)设置为该节点的左孩子节点;只有右孩子结点,相同的处理,将该节点的父节点的左(或者右)孩子节点(看本身该节点处于其父节点的左还是右孩子节点)设置为该节点的右孩子节点。
3)当该节点左孩子和右孩子都不为空时,我们要找到他的后继(前驱结点也行)结点y去替换掉当前的结点的位置,分两种情况:
<1>当后继结点y直接是该节点的右孩子,直接替换。把该节点的左子树挂到后继结点的左子树上
Transplant(x,y);
y.left=x.left;
y.left.p=y;
<2>当后继结点y不是该节点的右孩子而是右子树上的最小键值的一个节点,根据二叉查找树的性质该后继结点没有左子树(如果有左子树那它就不会是最小的键值结点了)。首先我们要把这个结点提取出来,用后继结点y的右孩子结点替换掉y的位置,再用y替换掉要删除的结点
if(y!=x.right){
Transplant(y,y.right);
y.right=x.right;
y.right.p=y;
}
Transplant(x,y);
y.left=x.left;
y.left.p=y;
替换函数为:
void Transplant(Entry u,Entry v){
if(u.p==null)//u为根节点
root=v;
else if(u==u.p.left)
u.p.left=v;
else
u.p.right=v;
if(v!=null)
v.p=u.p;
}
好了到这里二叉查找树的基本函数都有了,遍历函数应该不用谢了,就是普通的二叉树遍历,下面是一个完整的二叉查找树实现例子
public class SearchTree {
Entry root=null;
public void print(){
InOrderTreeWalk(root);
}
void InOrderTreeWalk(Entry x){
if(x!=null){
InOrderTreeWalk(x.left);
System.out.print(x.key+" ");
InOrderTreeWalk(x.right);
}
}
Entry TreeMinimum(Entry x) {
if (x.left != null)
x = x.left;
return x;
}
Entry TreeSuccessor(Entry x) {
if (x.right != null) {
return TreeMinimum(x);
} else {
Entry y = x.p;
while (y != null && x == y.right) {
x = y;
y = y.p;
}
return y;
}
}
void TreeInsert(Entry x) {
Entry k = root;
Entry y=null;
while (k != null) {
y=k;
if (x.key < k.key)
k = k.left;
else
k = k.right;
}
if(y!=null)
if(x.key<y.key)
y.left=x;
else
y.right=x;
else
root=x;
x.p=y;
}
void Transplant(Entry u,Entry v){
if(u.p==null)
root=v;
else if(u==u.p.left)
u.p.left=v;
else
u.p.right=v;
if(v!=null)
v.p=u.p;
}
void TreeDelete(Entry x){
Entry p=x.p;
if(x.left==null)
Transplant(x,x.right);
else if(x.right==null)
Transplant(x,x.left);
else{
Entry y=TreeMinimum(x.right);
if(y!=x.right){
Transplant(y,y.right);
y.right=x.right;
y.right.p=y;
}
Transplant(x,y);
y.left=x.left;
y.left.p=y;
}
}
Entry TreeSearch(int key){
Entry x=root;
while(x!=null&&x.key!=key){
if(x.key<key)
x=x.right;
else
x=x.left;
}
return x;
}
public static void main(String args[]){
SearchTree tree=new SearchTree();
tree.TreeInsert(new Entry(15));
tree.TreeInsert(new Entry(6));
tree.TreeInsert(new Entry(18));
tree.TreeInsert(new Entry(3));
tree.TreeInsert(new Entry(8));
tree.TreeInsert(new Entry(7));
tree.TreeInsert(new Entry(17));
tree.TreeInsert(new Entry(20));
tree.TreeInsert(new Entry(2));
tree.TreeInsert(new Entry(4));
tree.TreeInsert(new Entry(13));
tree.TreeInsert(new Entry(9));
tree.print();
System.out.println();
int key=8;
Entry x=tree.TreeSearch(key);
tree.TreeDelete(x);
tree.print();
}
}
class Entry {
int key;
Entry left;
Entry right;
Entry p;
public Entry(int key) {
this.key = key;
left = null;
right = null;
p = null;
}
}