Map和Set

目录

搜索树

概念

操作-查找

操作-插入

操作-删除(难点)

性能分析

搜索树与java 类集的关系

搜索

概念及场景

模型

Map的使用

关于Map的说明

关于Map.Entry的说明

Map 的常用方法说明

Set 的说明

常见方法说明

哈希表

概念

冲突-概念

冲突-避免

冲突-避免-哈希函数设计

常见哈希函数

冲突-避免-负载因子调节(重点掌握)

冲突-解决

冲突-解决-闭散列

冲突-解决-开散列/哈希桶(重点掌握)

冲突严重时的解决办法

练习题


搜索树

概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

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

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

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

· 中序遍历的结果是有序的

int[] array = {5,3,4,1,7,8,2,6,0,9};


操作-查找

代码展示:

/**
     * 在二叉搜索树里面搜索一个数字
     */
    public boolean search(int val){
        // 如果该树是一颗空树,那说明一定没有要查找的数据
        if (root == null){
            return false;
        }
        // 另外一种情况
        TreeNode node = new TreeNode(val);
        TreeNode cur = root;
        while (cur!=null){
            if (cur.val == node.val){
                return true;
            }
            if (cur.val > node.val){
                cur = cur.left;
            }
            if (cur.val < node.val){
                cur = cur.right;
            }
        }
        // 如果经过上述没找,那就说明这颗树中没有找到想要的节点
        return false;
    }

测试代码:

    /**
     * 检验二叉搜索树插入数据的
     * @param args
     */
    public static void main1(String[] args) {
        BinarySearchTree binarySearchTree = new BinarySearchTree();
        binarySearchTree.insert(5);
        binarySearchTree.insert(3);
        binarySearchTree.insert(7);
        binarySearchTree.insert(1);
        binarySearchTree.insert(4);
        binarySearchTree.insert(8);
        binarySearchTree.insert(6);
        binarySearchTree.insert(0);
        binarySearchTree.insert(2);
        binarySearchTree.insert(9);
        binarySearchTree.postOrder2(binarySearchTree.root);
    }

操作-插入

1. 如果树为空树,即根 == null,直接插入

2. 如果树不是空树,按照查找逻辑确定插入位置,插入新结点

代码展示:

/**
     * 在二叉搜索树里面搜索一个数字
     */
    public boolean search(int val){
        // 如果该树是一颗空树,那说明一定没有要查找的数据
        if (root == null){
            return false;
        }
        // 另外一种情况
        TreeNode node = new TreeNode(val);
        TreeNode cur = root;
        while (cur!=null){
            if (cur.val == node.val){
                return true;
            }
            if (cur.val > node.val){
                cur = cur.left;
            }
            if (cur.val < node.val){
                cur = cur.right;
            }
        }
        // 如果经过上述没找,那就说明这颗树中没有找到想要的节点
        return false;
    }

测试代码:

    /**
     * 检验二叉搜索树插入数据的
     * @param args
     */
    public static void main1(String[] args) {
        BinarySearchTree binarySearchTree = new BinarySearchTree();
        binarySearchTree.insert(5);
        binarySearchTree.insert(3);
        binarySearchTree.insert(7);
        binarySearchTree.insert(1);
        binarySearchTree.insert(4);
        binarySearchTree.insert(8);
        binarySearchTree.insert(6);
        binarySearchTree.insert(0);
        binarySearchTree.insert(2);
        binarySearchTree.insert(9);
        binarySearchTree.postOrder2(binarySearchTree.root);
    }

注:这个代码中的遍历是,中序遍历


操作-删除(难点)

设待删除结点为 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【替罪羊的方式】

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

/**
     * 找指定节点的父亲节点
     */
    public TreeNode searchParent(int val){
        // 如果该树是一颗空树,那说明一定没有要查找的数据
        if (root == null){
            return null;
        }
        // 另外一种情况
        TreeNode node = new TreeNode(val);
        TreeNode cur = root;
        TreeNode parent = null;  // 记录父节点
        while (cur != null) {
            if (cur.val > val) {
                parent = cur;  // 记录当前节点为父节点
                cur = cur.left;
            } else if (cur.val < val) {
                parent = cur;  // 记录当前节点为父节点
                cur = cur.right;
            } else {
                return parent; // 找到了,返回父节点
            }
        }
        // 如果经过上述没找,那就说明这颗树中没有找到想要的节点
        return null;   //没有找到指定节点
    }



    /**
     * 从二叉搜索树中删除元素
     */
    public void delect(int val){
        // 如果这是颗空树,那说明没什么好删的
        if (root == null){
            return;
        }
        TreeNode cur = search(val);  // 想要删除的节点
        TreeNode parent = searchParent(val);  // 找到想伤处节点的父亲节点

        // 1.cur.left == null
        if (cur.left == null){
            if (cur == root){
                root = cur.right;
            }else {
                if (cur == parent.left){
                    parent.left = cur.right;
                }
                if (cur == parent.right){
                    parent.right = cur.right;
                }
            }
        }

        // 2.cur.right == null
        if (cur.right == null){
            if (cur == root){
                root = cur.left;
            }else {
                if (cur == parent.left){
                    parent.left = cur.left;
                }
                if (cur == parent.right){
                    parent.right = cur.left;
                }
            }
        }


        // 3.cur.left != null && cur.right != null【难点】
        if (cur.left != null && cur.right != null){
            TreeNode tp = cur;
            TreeNode t = cur.right;
            while (t.left!=null){
                tp = t;
                t = t.left;
            }
            cur.val = t.val;
            if (t == tp.left){
                tp.left = t.right;
            }else {
                tp.right = t.right;
            }

        }


    }

性能分析

插入和删除操作都必须先查找查找效率代表了二叉搜索树中各个操作的性能。

对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多

但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鸭梨大大大

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值