算法导论——(2)二叉查找树的实现

正在学习算法导论,根据书上的伪代码和思想实现二叉查找树。
主要方法有:
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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值