【数据结构】 | java中 map和set 详解

这篇具有很好参考价值的文章主要介绍了【数据结构】 | java中 map和set 详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🎗️ 博客新人,希望大家一起加油进步
🎗️ 乾坤未定,你我皆黑马

我们首先来看一下集合的框架结构:
【数据结构】 | java中 map和set 详解
Set实现了Collection接口,Map是一个单独存在的接口。

而下面又分别各有两个类,分别是TreeSet(HashSet)和 HashSet(HashMap)
Map和Set的作用是用来查找和搜索的;以后涉及到查找和搜索的可以选择使用这两个接口下面具体的类。
搜索树(“Tree”)

1、搜索树(“Tree”)

1.1 概念

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

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

如图所示:
【数据结构】 | java中 map和set 详解

1.2 操作 - 查找

思路如图:
【数据结构】 | java中 map和set 详解

  • 代码实现
/**
     * 查找二叉搜索树中指定的val值
     *
     * @param val
     * @return
     */
    public TreeNode find(int val) {
        TreeNode cur = root;
//        if(null == cur) {
//            return null;
//        }
        while (cur != null) {
            if (cur.val > val) {
                cur = cur.right;
            } else if (cur.val < val) {
                cur = cur.left;
            } else {
                return cur;
            }
        }
        return null;
    }
1.3 操作 - 插入
  • 如果树为空树,即根 == null,直接插入
  • 如果树不是空树,按照查找逻辑确定插入位置,插入新节点
  • 注意: 一般情况下是不插入相同的数据的
    【数据结构】 | java中 map和set 详解
  • 代码实现
/**
     * 插入一个数据
     *
     * @param val
     */
    public void insert2(int val) {
        if (root == null) {
            root = new TreeNode(val);
            return;
        }
        TreeNode cur = root;
        TreeNode parent = null;
        while (cur != null) {
            if(cur.val < val) {
                parent = cur;
                cur = cur.right;
            }
            if(cur.val > val) {
                parent = cur;
                cur = cur.left;
            }
        }
        //走完之后判断前一个结点是否比val大
        if(cur.val < val) {
            //parent.right.val = val;
            parent.right = new TreeNode(val);
        }
        if(cur.val > val) {
            //parent.left.val = val;
            parent.left = new TreeNode(val);
        }
    }
1.4 操作-删除(难点)

设待删除结点为 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.4.1 三种情况下也有具体要细分的:
  • 待删除的左边为空 cur.left == null ,如图所示:
    【数据结构】 | java中 map和set 详解
  • 待删除的右边为空 cur.left == null ,如图所示:

【数据结构】 | java中 map和set 详解

  • 待删除的节点左右边都不为空 .cur.left != null && cur.right != null ,如图所示:

思路:找到删除节点cur的右边节点中最小的值,替换到cur处,最后把替换到最后的一个节点给删除掉即可。
【数据结构】 | java中 map和set 详解
【数据结构】 | java中 map和set 详解

  • 代码实现
/**
     * 删除值为val的节点
     * @param val
     */
    //自己练习写的
    public void remove(int val) {
        TreeNode cur = root;
        TreeNode parent = null; //用于记录cur的前一个节点
        while(cur != null) {
            if(cur.val == val) {
                removeNode2(parent,cur);
                return;
            }else if(cur.val > val) {
                parent = cur;
                cur = cur.left;
            }else {
                parent = cur;
                cur = cur.right;
            }
        }
    }

	//自己练习写的
    private void removeNode2(TreeNode parent, TreeNode cur) {
        //第一种情况 cur是root
        if(cur.left == null) {
            if(cur == root) {
                root = cur.right; //此时cur所在节点是要删除的节点
                return;
            } else {
                if(cur == parent.right) {
                    //第二种情况 cur不是root,cur是parent.right
                    parent.right = cur.right;
                } else {
                    //第三种情况 cur不是root,cur是parent.left
                    parent.left = cur.right;
                }
            }
        } else if(cur.right == null) {
                if(cur == root) {     //第一种情况 cur是root
                    root = cur.left; //此时cur所在节点是要删除的节点
                    return;
                } else {
                    if(cur == parent.right) {
                        //第二种情况 cur不是root,cur是parent.right
                        parent.right = cur.left;
                    } else {
                        //第三种情况 cur不是root,cur是parent.left
                        parent.left = cur.left;
                    }
                }
        } else {     //cur左右都不为空节点  思路:找到cur右边节点最小的值与之进行交换就可以了
            TreeNode targetP = cur;
            TreeNode target = cur.right;
            while(target.left != null) {
                targetP = target;
                target = target.left;
            }
            //走到这说明target的左节点为空了
            //进行交换
            cur.val = target.val;
            if(target == targetP.left) {
                targetP.left = target.right; //target.right为空也没事,给到targetP.left,说明targetP节点左侧为空了
            }
            if(target == targetP.right) {
                targetP.right = target.right;  //这种情况是target没有左节点,相当于cur右边节点是个右单树
            }
        }
    }
1.5 性能分析
  • 插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。

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

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

最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:logN
最差情况下,二叉搜索树退化为单支树,其平均比较次数为:N/2

  • TreeMap 和 TreeSet 即 java 中利用搜索树实现的 Map 和 Set;实际上用的是红黑树,而红黑树是一棵近似平衡的二叉搜索树,即在二叉搜索树的基础之上 + 颜色以及红黑树性质验证。

2、搜索

2.1 概念及场景

Map和set是一种专门用来进行搜索的容器或者数据结构,其搜索的效率与其具体的实例化子类有关。以前常见的搜索方式有:

  1. 直接遍历,时间复杂度为O(N),元素如果比较多效率会非常慢
  2. 二分查找,时间复杂度为 ,但搜索前必须要求序列是有序的
    上述排序比较适合静态类型的查找,即一般不会对区间进行插入和删除操作了,而现实中的查找比如:
  3. 根据姓名查询考试成绩
  4. 通讯录,即根据姓名查询联系方式
  5. 不重复集合,即需要先搜索关键字是否已经在集合中可能在查找时进行一些插入和删除的操作,即动态查找,那上述两种方式就不太适合了,本节介绍的Map和Set是一种适合动态查找的集合容器。
2.2 模型

一般把搜索的数据称为关键字(Key),和关键字对应的称为值(Value),将其称之为Key-value的键值对,所以模型会有两种:

  1. 纯 key 模型,比如:
    有一个英文词典,快速查找一个单词是否在词典中快速查找某个名字在不在通讯录中
  2. Key-Value 模型,比如:
    统计文件中每个单词出现的次数,统计结果是每个单词都有与其对应的次数:<单词,单词出现的次数>
    梁山好汉的江湖绰号:每个好汉都有自己的江湖绰号

而Map中存储的就是key-value的键值对,Set中只存储了Key。

【数据结构】 | java中 map和set 详解

3. Map的使用

3.1 关于Map的说明

Map是一个接口类,该类没有继承自Collection,该类中存储的是<K,V>结构的键值对,并且K一定是唯一的,不能重复。

3.2 关于Map.Entry<K, V>的说明

Map.Entry<K, V> 是Map内部实现的用来存放<key, value>键值对映射关系的内部类,该内部类中主要提供了<key, value>的获取,value的设置以及Key的比较方式。

方法 解释
K getKey() 返回 entry 中的 key
V getValue() 返回 entry 中的 value
V setValue(V value) 将键值对中的value替换为指定value

注意:Map.Entry<K,V>并没有提供设置Key的方法

3.3 Map 的常用方法说明

【数据结构】 | java中 map和set 详解

注意:

  • Map是一个接口,不能直接实例化对象, 如果要实例化对象只能实例化其实现类TreeMap或者HashMap
  • Map中存放键值对的Key是唯一的,value是可以重复的
  • 在TreeMap中插入键值对时,key不能为空,否则就会抛NullPointerException异常,value可以为空。但是HashMap的key和value都可以为空。
  • Map中的Key可以全部分离出来,存储到Set中来进行访问(因为Key不能重复)。
  • Map中的value可以全部分离出来,存储在Collection的任何一个子集合中(value可能有重复)。
  • Map中键值对的Key不能直接修改,value可以修改,如果要修改key,只能先将该key删除掉,然后再来进行重新插入。
  • TreeMap和HashMap的区别如下图所示:
    【数据结构】 | java中 map和set 详解

4. Set的说明

Set 的官方文档:https://docs.oracle.com/javase/8/docs/api/java/util/Set.html

4.1 常见方法说明
方法 解释
boolean add(E e) 添加元素,但重复元素不会被添加成功
void clear() 清空集合
boolean contains(Object o) 判断 o 是否在集合中
Iterator iterator() 返回迭代器
boolean remove(Object o) 删除集合中的 o
int size() 返回set中元素的个数
boolean isEmpty() 检测set是否为空,空返回true,否则返回false
Object[] toArray() 将set中的元素转换为数组返回
boolean containsAll(Collection<?> c) 集合c中的元素是否在set中全部存在,是返回true,否则返回false
boolean addAll(Collection<? extendsE> c) 将集合c中的元素添加到set中,可以达到去重的效果

注意:

  1. Set是继承自Collection的一个接口类
  2. Set中只存储了key,并且要求key一定要唯一
  3. TreeSet的底层是使用Map来实现的,其使用key与Object的一个默认对象作为键值对插入到Map中的
  4. Set最大的功能就是对集合中的元素进行去重
  5. 实现Set接口的常用类有TreeSet和HashSet,还有一个LinkedHashSet,LinkedHashSet是在HashSet的基础
    上维护了一个双向链表来记录元素的插入次序。
  6. Set中的Key不能修改,如果要修改,先将原来的删除掉,然后再重新插入
  7. TreeSet中不能插入null的key,HashSet可以。
  8. TreeSet和HashSet的区别 如下图所示:
Set底层结构 TreeSet HashSet
底层结构 红黑树 哈希桶
插入/删除/查找时间复杂度 0(Log N) O(1)
是否有序 关于Key有序 不一定有序
线程安全 不安全 不安全
插入/删除/查找区别 按照红黑树的特性来进行插入和删除 1. 先计算key哈希地址 2. 然后进行插入和删除
比较与覆写 key必须能够比较,否则会抛出ClassCastException异常 自定义类型需要覆写equals和hashCode方法
应用场景 需要Key有序场景下 Key是否有序不关心,需要更高的时间性能

解决下面的三个问题:

  1. 统计10W个数据当中,不重复的数据?(去重)
  2. 统计10W个数据当中,第一个重复的数据?
  3. 统计10W个数据当中,每个数据出现的次数?(对应的关系)
  • 解题思路: 利用set可以达到去重的效果,出现的次数可以用到K - V 模型,即是map

  • 代码实现

import java.util.*;

public class Test {
    //1、统计10W个数据当中,不重复的数据?[去重]
    public static void func1(int[] array) {
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < array.length; i++) {
            set.add(array[i]);
        }
        System.out.println(set);
    }
    //2、统计10W个数据当中,第一个重复的数据?
    public static void func2(int[] array) {
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < array.length; i++) {
            if(!set.contains(array[i])) {
                set.add(array[i]);
            }else {
                System.out.println(array[i]);
                break;
            }
        }
    }
    //3、统计10W个数据当中,每个数据出现的次数? 对应的关系
    public static void func3(int[] array) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < array.length; i++) {
            int key = array[i];
            if(map.get(key) == null) {
                map.put(key, 1);
            }else {
                int val = map.get(key);
                map.put(key, val+1);
            }
        }
        //利用foreach语句 来遍历Map.Entry<K, V>导出的K-V 对应的关系来获取次数
        for (Map.Entry<Integer, Integer> entry:map.entrySet()) {
            System.out.println("key: "+ entry.getKey()+"出现了: "+entry.getValue()+" 次");
        }
    }

    public static void main(String[] args) {
        int[] array = new int[10_0000];
        Random random = new Random();
        for (int i = 0; i < array.length; i++) {
            array[i] = random.nextInt(5_0000);
        }
        func1(array);
        func2(array);
        func3(array);
    }
}

🎗️🎗️🎗️ 好啦,到这里我们的 Set 和 Map 的分享就没了,如果感觉做的还不错的可以点个赞,关注一下,你的支持就是我继续下去的动力,蟹蟹大家了,我们下期再见,拜拜~ ☆*: .。. o(≧▽≦)o .。.:*☆文章来源地址https://www.toymoban.com/news/detail-409473.html

到了这里,关于【数据结构】 | java中 map和set 详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • Java02-迭代器,数据结构,List,Set ,Map,Collections工具类

    Java02-迭代器,数据结构,List,Set ,Map,Collections工具类

    目录 什么是遍历? 一、Collection集合的遍历方式 1.迭代器遍历 方法 流程 案例 2. foreach(增强for循环)遍历 案例 3.Lamdba表达式遍历 案例 二、数据结构 数据结构介绍 常见数据结构 栈(Stack) 队列(Queue) 链表(Link) 散列表(Hash Table) 树(Tree) List接口 ArraysList集合 Linked

    2024年02月14日
    浏览(34)
  • Java学数据结构(3)——树Tree & B树 & 红黑树 & Java标准库中的集合Set与映射Map & 使用多个映射Map的案例

    Java学数据结构(3)——树Tree & B树 & 红黑树 & Java标准库中的集合Set与映射Map & 使用多个映射Map的案例

    1.B树,阶M,数据树叶上,根的儿子数在2和M之间,除根外,非树叶节点儿子为M/2和M之间; 2.B树的插入引起分裂,B树的删除,引起合并和领养; 3.红黑树,根是黑的,红色节点的儿子必须是黑的,所有路径的黑色节点数相同; 4.红黑树的插入,颜色翻转,单旋转,插入节点定

    2024年02月11日
    浏览(13)
  • 「数据结构」Map&Set

    「数据结构」Map&Set

    🎇 个人主页 :Ice_Sugar_7 🎇 所属专栏 :Java数据结构 🎇 欢迎点赞收藏加关注哦! Map和Set是专门用来进行搜索的容器或者数据结构,它们适合动态查找(即在查找时可能会进行一些插入和删除的操作) 我们一般把搜索的数据称为 (Key) ,和对应的称为 值(

    2024年02月22日
    浏览(14)
  • [数据结构]-map和set

    [数据结构]-map和set

    前言 作者 : 小蜗牛向前冲 名言 : 我可以接受失败,但我不能接受放弃   如果觉的博主的文章还不错的话,还请 点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正   目录 一、键值对 二、set 1、set的基本知识 2、set的使用  三、map 1、map的基本

    2024年02月04日
    浏览(16)
  • 【高阶数据结构】封装Map和Set

    【高阶数据结构】封装Map和Set

    (꒪ꇴ꒪(꒪ꇴ꒪ )🐣,我是 Scort 目前状态:大三非科班啃C++中 🌍博客主页:张小姐的猫~江湖背景 快上车🚘,握好方向盘跟我有一起打天下嘞! 送给自己的一句鸡汤🤔: 🔥真正的大师永远怀着一颗学徒的心 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏 🎉🎉

    2024年01月20日
    浏览(16)
  • 【1++的数据结构】之map与set(一)

    【1++的数据结构】之map与set(一)

    👍作者主页:进击的1++ 🤩 专栏链接:【1++的数据结构】 像list vector dequeue等这样的容器我们称为序列式容器,原因是由于其底层是线性的数据结构,存储的是元素本身。 关联式容器 与序列式容器的区别在于:关联式容器中存储的是键值对,其数据检索时效率更高。 那么什

    2024年02月11日
    浏览(9)
  • 数据结构,Map和Set的使用方法

    数据结构,Map和Set的使用方法

    在数据结构中我们经常会使用到 Map 和 Set ,Map 和 Set 到底是什么,它怎样去使用呢?因此博主整理出 Map 和 Set 这两个接口的介绍与使用方法。 目录 1. 啥是Map和Set? 1.1 Map和Set的模型 2. Map的使用 2.1Map的说明 2.2 Java中Map常用的方法 3. Set的使用 3.1Java中Set的常用方法  Map 和 Set

    2023年04月26日
    浏览(10)
  • Map、Set和哈希表(数据结构系列14)

    Map、Set和哈希表(数据结构系列14)

    目录 前言: 1.搜索树 1.1概念 1.2插入 1.3查找 1.4删除 1.5二叉搜索树整体代码展示  2. Map和Set的讲解 2.1 Map的说明 2.1.1Map的方法 2.2 Set 的说明 2.2.1Set的方法 3.哈希表 3.1哈希表的概念 3.2哈希冲突 3.3冲突的避免 3.4哈希冲突的解决 3.4.1闭散列 3.4.2开散列 结束语: 这节中小编主要与

    2024年02月07日
    浏览(11)
  • Map,List,Set 等集合以及底层数据结构

    Map,List,Set 等集合以及底层数据结构

    集合类存放于java.util包中。集合类存放的都是对象的引用,而非对象本身。常见的集合主要有三种——Set(集)、List(列表)和Map(映射)。其中,List和Set 都 实现 了 Collection 接口,并且List和Set也是接口,而 Map 为独立接口 。常见的实现类如下: List 的实现类有:ArrayList、

    2024年02月09日
    浏览(12)
  • 【数据结构】二叉搜索树与Map和Set

    【数据结构】二叉搜索树与Map和Set

    目录 ♫二叉搜索树 ♪什么是二叉搜索树 ♪二叉搜索树的特性 ♪模拟实现二叉搜索树 ♫Map ♪什么是Map ♪Map的内部类 ♪Map的常用方法 ♪Map的遍历 ♫Set  ♪什么是Set ♪Set的常用方法 ♪Set的遍历 ♪什么是二叉搜索树 二叉搜索树又称二叉排序树,是一种特殊的二叉树,这颗树

    2024年02月07日
    浏览(10)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包