二叉搜索树及简单电话本

一.概念

二叉搜索树又称二叉排序树(纯 key 模型,且 key值不能重复,二叉搜索树的中序遍历是有序的),它或者是一棵空树**,或者是具有以下性质的二叉树:

若它的左子树不为空,则左子树上所有节点的值都小于根节点的值

若它的右子树不为空,则右子树上所有节点的值都大于根节点的值

它的左右子树也分别为二叉搜索树

二.搜索树操作

1.查找:在搜索树中查找 key 值,若找到返回该节点,未找到返回空节点。时间复杂度 O(log(N)) - O(N)  

思路:

public Node search(int key){
        Node cur = root;
        while(cur != null){
            if(key == cur.key){
                return cur;
            }else if(key > cur.key){
                cur = cur.right;
            }else{
                cur = cur.left;
            }
        }
        return null;
    }

2.插入:如果树为空,直接插入,否则按照查找逻辑确定插入位置进行插入

思路:

public boolean insert(int key){
        // 如果该树是一个空节点,直接插入,即让该节点为 根结点 root
        if(root == null){
            root = new Node(key);
            return true;
        }
        // 寻找 key 值的合理位置,若该值已有则插入失败
        Node cur = root;
        Node parent = null;
        while(cur != null){
            if(key == cur.key){
                return false;
            }else if(key < cur.key){
                parent = cur;
                cur = cur.left;
            }else{
                parent = cur;
                cur = cur.right;
            }
        }
        // 插入
        Node node = new Node(key);
        if(key > parent.key){
            parent.right = node;
        }else{
            parent.left = node;
        }
        return true;
    }

3.删除

设待删除结点为 cur, 待删除结点的双亲结点为 parent

1. cur.left == null

  1.  cur 是 root,则 root = cur.right
  2.  cur 不是 root,cur 是 parent.left,则 parent.left = cur.right
  3.  cur 不是 root,cur 是 parent.right,则 parent.right = cur.right

2. cur.right == null

  1.  cur 是 root,则 root = cur.left
  2. cur 不是 root,cur 是 parent.left,则 parent.left = cur.left
  3. cur 不是 root,cur 是 parent.right,则 parent.right = cur.left

3. cur.left != null && cur.right != null

需要使用替换法进行删除,即在它的右子树中寻找关键码最小的(或者在左子树寻找关键码最大的),用它的值填补到被删除节点中,再来处理该结点的删除问题

public boolean remove(int key){
        Node cur = root;
        Node parent = null;
        // 先找到待删除节点以及他的父亲节点
        while(cur != null){
            if(cur.key == key){// 找到,准备删除
                removeNode(parent,cur);
                return true;
            }else if(key > cur.key){
                parent = cur;
                cur = cur.right;
            }else{
                parent = cur;
                cur = cur.left;
            }
        }
        return false;
    }

private void removeNode(Node parent, Node cur) {
        // 进行删除
        if(cur.left == null){
            if(cur == root){
                root = cur.right;
            }else if(cur == parent.left){
                parent.left = cur.right;
            }else{
                parent.right = cur.right;
            }
        }else if(cur.right == null){
            if(cur == root){
                root = cur.left;
            }else if(cur == parent.left){
                parent.left = cur.left;
            }else{
                parent.right = cur.left;
            }
        }else{// 替换法:在右子树寻找最小的(或者左子树中最大的)
            Node goatParent = cur;
            Node goat = cur.right;
            while(goat.left != null){
                goatParent = goat;
                goat = goat.left;
            }
            cur.key = goat.key;
            // 判断 goat 是 goatParent 的左孩子还是右孩子
            if(goat == goatParent.left){
                goatParent.left = goat.right;
            }else{
                goatParent.right = goat.right;
            }
        }
    }

完整测试代码

三.电话本 key - Value 模型

基本操作:查找,插入,更新。与搜索树思路相同,只是多考虑一个 Value。(key 允许重复,Value 不允许重复)

public class Contact {
    public static class Node{
        String name;
        String phone;
        Node left;
        Node right;

        public Node(String name, String phone) {
            this.name = name;
            this.phone = phone;
        }
    }
    private Node root = null;
    // 查找,没有找到返回 null,否则返回这个人的电话
    public String search(String name){
        Node cur = root;
        while(cur != null){
            if(name == cur.name){
                return cur.phone;
            }else if(name.compareTo(cur.name) > 0){
                cur = cur.right;
            }else{
                cur = cur.left;
            }
        }
        return null;
    }
    // 插入,若不存在则插入,若存在则插入失败
    public boolean insert(String name, String phone){
        Node cur = root;
        Node parent = null;
        while(cur != null){
            if(name == cur.name){
                return false;
            }else if(name.compareTo(cur.name) > 0){// String类型不能直接比较
                parent = cur;
                cur = cur.right;
            }else{
                parent = cur;
                cur = cur.left;
            }
        }
        Node node = new Node(name,phone);
        if(parent.name.compareTo(name) > 0){
            parent.left = node;
        }else{
            parent.right = node;
        }
        return true;
    }
    // 更新电话本,若存在该用户更新他的电话,不存在返回 false
    public boolean update1(String name,String phone){
        Node cur = root;
        while(cur != null){
            if(name == cur.name){
                cur.phone = phone;
                return true;
            }else if(name.compareTo(cur.name) > 0){
                cur = cur.right;
            }else{
                cur = cur.left;
            }
        }
        return false;
    }
    // 更新电话本,若存在该用户更新他的旧电话,否则返回 null
    public String update2(String name,String phone){
        Node cur = root;
        while(cur != null){
            if(name == cur.name){
                String oldPhone = cur.phone;
                cur.phone = phone;
                return oldPhone;
            }else if(name.compareTo(cur.name) > 0){
                cur = cur.right;
            }else{
                cur = cur.left;
            }
        }
        return null;
    }
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值