二叉查找树(增、删、查)

本文详细介绍了二叉查找树的基本概念及其核心操作:增加、查找和删除节点的具体实现过程,并提供了非递归实现的示例代码。

定义

二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)
它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。 –from 百度百科

增加(put)

原理: 按照大的向右小的向左原则,沿着树的根节点往下找,找到第一个为空的节点或者节点的key和目标key相同时结束,前者插入,后者替换。

/**
 * @Description: 插入节点
 * @param key
 * @param value
 * @author wjc920
 * @date 2018年6月26日
 */
public void put(K key, V value) {
    Node toPut=new Node(key, value);
    //在遍历树之前,先判断树是否为空,若空着执行插入,结束
    if(root==null) {
        root=toPut;
        return;
    }
    Node cur=root;
    while(true) {
        int cmp=key.compareTo(cur.key);               
        if (cmp < 0){
            //如果代码执行到这里,下一步将对cur的左子树遍历,
            //在遍历左子树之前先判断是否为空,若空着执行插入,结束
            if(cur.left==null) {       
                cur.left=toPut;
                break;
            }
            cur=cur.left;                             
        }else if (cmp > 0) {  
            //如果代码执行到这里,下一步将对cur的右子树遍历,
            //在遍历右子树之前先判断是否为空,若空着执行插入,结束
            if(cur.right==null) {
                cur.right=toPut;
                break;
            }
            cur=cur.right;                            
        }else {                                             
            cur.value=toPut.value;
            break;
        }
    }
}

注:非递归

查找

原理: 按照大的向右小的向左原则,沿着树的根节点往下找,找到第一个为空的节点或者节点的key和目标key相同时结束,前者返回空,后者返回值。

/**
 * @Description: 获取键key的值
 * @param key
 * @return
 * @author wjc920
 * @date 2018年6月26日
 */
public V get(K key) {
    return get(root, key).value;
}

private Node get(Node node, K key) {
    if (node == null)
        return null;
    int cmp = key.compareTo(node.key);
    if (cmp < 0)
        return get(node.left, key);
    else if (cmp > 0)
        return get(node.right, key);
    else
        return node;
}

删除

原理: 按照大的向右小的向左原则,沿着树的根节点往下找,找到第一个为空的节点或者节点的key和目标key相同时结束,前者不执行任何操作,后者需要分情况处理:
1. 若待删除的节点只有一个子节点(对应代码中情况2和3),则用子节点替换该节点即可,结束;
2. 若待删除节点没有子节点(对应代码中情况4),直接删除,结束;
3. 若待删除节点有两个子节点(对应代码中情况1),则查找该节点的后继节点,两者交换,然后将后继节点设置为待删除节点,此时回到情况1或2。

/**
 * @Description: 删除操作的非递归实现
 * @param key
 * @return   
 * @author wjc920  
 * @date 2018年6月30日
 */
public V remove(K key) {
    Node cur=root,target,replace,p=null;
    V result;
    while(cur!=null) {                                //寻找target,target.key==key
        int cmp=key.compareTo(cur.key);               //寻找target,target.key==key
        if (cmp < 0){                                 //寻找target,target.key==key
            p=cur;                                    //寻找target,target.key==key
            cur=cur.left;                             //寻找target,target.key==key
        }else if (cmp > 0) {                          //寻找target,target.key==key
            p=cur;                                    //寻找target,target.key==key 
            cur=cur.right;                            //寻找target,target.key==key
        }else                                         //寻找target,target.key==key    
            break;                                    //寻找target,target.key==key
    }
    target=cur;
    if(target==null)                                  //如果target==null,则不需要删除,返回null
        return null;                                  //如果target==null,则不需要删除,返回null
    result=target.value;                              //如果target!=null,则需要删除,先将target的value保存,作为返回结果
    if(target.left!=null) {
        if(target.right!=null) {                      //1 如果target.left!=null且target.right!=null
            p=target;                                 //找后继节点,即大于target的最小节点
            cur=target.right;                         //找后继节点,即大于target的最小节点
            while(cur.left!=null) {                   //找后继节点,即大于target的最小节点
                p=cur;                                //找后继节点,即大于target的最小节点
                cur=cur.left;                         //找后继节点,即大于target的最小节点
            }                                         //找后继节点,即大于target的最小节点

            replace=cur;                              //将后继节点替换tagert
            target.key=replace.key;                   //将后继节点替换tagert
            target.value=replace.value;               //将后继节点替换tagert
            if(replace.right!=null) {                 //1.1替换后,如果replace.right!=null
                replace.key=replace.right.key;        //用右节点替换replace,删除右节点
                replace.value=replace.right.value;    //用右节点替换replace,删除右节点
                replace.right=null;                   //用右节点替换replace,删除右节点
            }else {                                   //1.2 替换后,如果replace.right==null
                if(p.left==replace) {                 //删除replace
                    p.left=null;                      //删除replace
                }else {                               //删除replace
                    p.right=null;                     //删除replace
                }                                     //删除replace
            }
        }else {                                       //2 如果target.left!=null且target.right==null
            target.key=target.left.key;               //用左节点替换target
            target.value=target.left.value;           //用左节点替换target
            target.right=target.left.right;           //用左节点替换target
            target.left=target.left.left;             //用左节点替换target
        }
    }else {
        if(target.right!=null) {                     //3 如果target.left==null且target.right!=null
            target.key=target.right.key;             //用右节点替换target
            target.value=target.right.value;         //用右节点替换target
            target.left=target.right.left;           //用右节点替换target
            target.right=target.right.right;         //用右节点替换target

        }else {                                      //4 如果target.left==null且target.right==null
            if(p.left==target) {                     //删除target
                p.left=null;                         //删除target
            }else {                                  //删除target
                p.right=null;                        //删除target
            }
        }
    }
    return result;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值