【数据结构】Java的HashMap 和 HashSet 大全笔记,写算法用到的时候翻一下,百度都省了!(实践篇)

news2024/12/23 1:17:17

本篇会加入个人的所谓鱼式疯言

❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言

而是理解过并总结出来通俗易懂的大白话,

小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.

🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 !!!

在这里插入图片描述

  1. HashSet

  2. HashMap

前言

在探索Java集合框架的丰富世界时,我们不可避免地会遇到两个至关重要的成员:HashMap和HashSet。这两个组件虽然在功能上有着明显的交集,但它们在内部实现、性能表现以及使用场景上却有着显著的差异。本文将深入探讨HashMap与HashSet的内部机制,比较它们的性能特点,并指导读者如何在实际开发中做出恰当的选择

一. HashSet

1. set 的初识

在这里插入图片描述

对于 set 来说, 继承自 Collection 的类, 可以由 SortedSetTreeSetHashSet 来实现。

对于 set 本身 来说, 只 存储 key 的值, 并不 存values , 并且这个 key是唯一的, 且 不可修改的

在本篇文章中将重点讲解 HashSet 来实现 Set 类

鱼式疯言

set 本身的含义有: 设置集合

Java集合框架 中, set 的含义就表示 集合

集合中的关键码 (key) 就有 两大特性 : 1. 无序性 2. 唯一性

2. set 的常见方法使用

在这里插入图片描述

如上图, 小编介绍几种常见的方法, 足够我们平常 面试和刷算法题 中使用了

如果还想了解的小伙伴可以 参考下面的官方文档 哦 💕 💕 💕 💕

set 官方文档介绍

3. 代码演示

class Test1{

    public static void main(String[] args) {
        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(2);
        set.add(3);
        set.add(4);
        set.add(5);

//        使用迭代器 接收
        Iterator<Integer> iterator = set.iterator();

//        输出迭代器
        while(iterator.hasNext()) {
            System.out.println(iterator.next());
        }



//        判断 4 是否存在
        if(set.contains(4)) {
            System.out.println("删除前"+ 4 + "存在!");
        } else  {
            System.out.println("删除后"+  4 + "不存在!");
        }


//        得到key 的个数
        System.out.println(set.size());

       set.remove(4);
        if(set.contains(4)) {
            System.out.println("删除后" +  4 + "存在!");
        } else  {
            System.out.println("删除后" +  4 + "不存在!");
        }

    }

}

在这里插入图片描述

  • add() 添加了 key 值 , 如果 set 中存在则 添加失败

  • contains() 检查 是否存在该 key

  • remove() 删除 某个key

  • size() 得到key 的个数

  • iterator 迭代器 , 用来得到 全部的key 的一个 整体的迭代器

鱼式疯言

补充说明

  • 对于 set 的用法主要是用于判断是否 有重复元素 , 并且进行 去重操作。 并且用HashSet 实现, 时间复杂度 可以达到 O(1)
  • 对于 HashSet 实现的 set 接口 , 是可以进行 插入 null 的

二. HashMap

1. Map 的初识

在这里插入图片描述

对于Map 而已, 该接口 不继承Collection 接口 , 可有 HashMap 或 TreeMap 实现,

并且 Map<K, V> 中存储的是 一对K和 V 的键值对

其中 K 是 关键码(key) 用来 作为标识 , 是用来转化为 哈希地址索引标识, 是 唯一的不可更改 , 不能重复

而 V 是 值 (value) , 用来存储具体需要 存储的数据

上面的解释, 可能小伙伴们还不是很能理解

不妨回忆下我们上篇文章的 哈希表的建立

其中数组的下标就可以作为 索引值 , 而key 就可以通过 某种哈希函数 来转化为 数组的下标

value 就可以刚好对应 数组下标位置对应的值

鱼式疯言

小知识 :

对于 HashMap 实现的Map 来说, 键值对都是可以置为 null 的。

2. Map.Entry<K, V>

Map.Entry<K,V> 是一种专门 存放键值对的一种类型 , 并且是 Map 的静态方法 , 可以 不需要对象调用

其实有下面三种方法 ,小编在这里就展示 前两个
在这里插入图片描述

下面我们来看看其演示过程

    public static void main(String[] args) {
        
//        entry
       Map.Entry<String , String> entry = Map.entry("s","t");
        System.out.println(entry.getValue());
        System.out.println(entry.getKey());
        

    }

在这里插入图片描述

如上图

其中 s 就代表 key 的关键码,可以用 getValue 获取到

t 就表示 value 的关键码 , 可以用 getKey 来 获取到。

这个类型 其实用的不多, 小伙伴们只需要了解一下即可。

鱼式疯言

补充说明 :

虽然小编上面说明有提供了 修改Value 的方法, 但是并 没有提供 修改 Key 的方法。
所以对于 key 来说, 是 不可修改的

3. Map 的常见方法使用

在这里插入图片描述

对于上述的方法来说, get ()getOrDefault()put() remove()keySet() , values() 等…

以上这些方法, 小编都会一一演示。

4. 代码演示

import java.util.*;
public class Test {
    public static void main(String[] args) {



        // 实例化一个 map  对象
        Map<String, String> map = new HashMap<>();
        map.put("小白", "dog");
        map.put("小黑", "cat");
        map.put("小头", "sleep");
        map.put(null, null);


        System.out.println("正在遍历 value 值: ");
        // 使用 values 演示得到的所有的value  的结果
        Collection<String> strings = map.values();
        for(String strings1 : strings) {
            System.out.print(strings1 + " ");
        }

        System.out.println();

        // 使用 keyset  演示所以得到的 key 的结果
        System.out.println("正在遍历 key 值: ");

        Set<String> strings1 = map.keySet();
        for (String str : strings1) {
            System.out.print(str+ " ");
        }

        System.out.println();

//        判断map 是否存在 某个特定的 value  和 key
        if(map.containsKey("小白")) {
            System.out.println("存在小白!");
            if (map.containsValue("dog")) {
                System.out.println("存在小白, 并且小白是条狗");
            } else {
                System.out.println("存在小白, 但是小白不是条狗!");
            }
        }


        // 获取小黄的value , 如果没有就会返回 defaultValue 的特定的value
      String ret =  map.getOrDefault("小黄", "不存在小黄, 
      但这里会返回一个小蓝");
        System.out.println(ret);

    }



}

在这里插入图片描述

  • 通过 get() 其中参数列表中填入的 key 的值, 然后 调用 get() 之后 , 就会得到该 key 所对应的 value 值

  • getOrvalue() 如果有 key 就返回 对应的value 值 , 如果没有就 返回后面那个参数的结果

  • put() 就相等于 插入元素 , 不仅要插入 key , 也要 插入key 所对应的value 。 从而得到 两者相关联一样对应的关系 的作用。

  • remove() , 是直接删除 key , 并且 一旦删除 key , 那么 对应的value 也会被删除。

  • keyset() , 这个方法的作用就在于 获取map 中所有的key 值 , 并且用前面讲解过的 Set<Key> 来接收。

  • values() 这个方法的含义就在于 获取map 中所有的 value值 , 返回值是一个Collection<value> 来接收。

  • containsKey() , 用于判断指定的 key 是否存在

  • containsValue() , 用于判断指定的 value 是否存在

鱼式疯言

补充说明:

  • 对于map 来说, key 是不可重复的, 但是 value 是可以重复 ,并且是可以修改的, 如果 一定要修改key 的值 , 就需要把 原先的key 删除 , 然后 添加一个新的key

  • 由于 key 是不可重复的 , 当我们返回 key 的集合 时, 就可以用set 来接收 ,因为set 的最大功能就是对元素 进行去重 , 达到每一个 关键码都是唯一性

  • 由于 value 是可以重复的, 当我们返回 value的集合 时 , 不可以用 set 来接收一般用Collection 来接收

  • 综上所得, 对于 set 的而言, 如果涉及到 单个元素的去重操作一般我们使用 set

    但如果有 两种关联属性 的话, 我们一般用 map建立键值对进行操作

三. 哈希桶实现哈希表

哈希桶的本质就是当出现哈希冲突时, 利用 链表把新的关键码(key) 插入原有的 key 的后面 , 把 一个大集合转化为一个小集合 来使用。

如果对这个概念还很模糊的小伙伴可以参考小编的上一篇文章哦 💕 💕 💕 💕

1. 哈希桶的代码展示

package hash;


public class KVHashBucket <K,V>{
    // 存放链表数组
   Node<K,V>[]array;

    // 实际元素个数
    int useSize;


    private static final int DEFAULTSIZE=10;


    // 定义一个内部类为节点
    static class Node<K,V> {
        V val;
        Node<K,V> next;

        K key;
        public Node(K key,V val) {
            this.key=key;
            this.val = val;
        }
    }



    public KVHashBucket() {
        array= (Node<K, V>[]) new Node[DEFAULTSIZE];

    }

    /**
     * 插入方法
     * @param val 需要插入的数据
     */
    void put(K key,V val) {

        // 判断是否满
        if (isFull()) {
            insertFunc2(key,val);
            return;
        }

        insertFunc1(key,val);

    }

    /**
     * 未满时普通插入
     * @param val 需要插入的数据
     */

    private void insertFunc1(K key,V val) {
        int sz=array.length;
        int k=key.hashCode();
        int index= k % sz;

        // 如果出现 key 重复 就修改 val 值
        Node<K,V> cur=array[index];
        while (cur != null) {
            if (cur.key == key) {
                cur.val=val;
                return;
            }
            cur=cur.next;
        }

        Node<K,V> node=new Node<K,V>(key,val);

        node.next=array[index];
        array[index]=node;
        useSize++;
    }

    /**
     * 扩容方法
     * @param val 插入数据
     * 先扩容一个新数组
     * 然后把旧数组整合放入新数组
     * 最后旧数组成为新数组
     */

    private void insertFunc2(K key ,V val) {
       Node<K,V> cur=null;

       Node<K,V>[] newArray= (Node<K, V>[]) new Node[2 * array.length];

        int newLength = 2 * array.length;

        for (int i = 0; i < array.length; i++) {

            cur=array[i];
            while (cur != null) {
                K m = cur.key;

                // 先让 node 记住 cur 的下个节点
                Node<K,V> node = cur.next;
                int k=m.hashCode();
                int index= k % newLength;

                cur.next = newArray[index];
                newArray[index] = cur;

                cur=node;
            }

        }

       Node<K,V> til=new Node<K,V>(key,val);
        int k=key.hashCode();
        int index=k%newLength;

        // 如果出现 key 重复 就修改 val 值
        Node<K,V> curN=array[index];
        while (curN != null) {
            if (curN.key == key) {
                curN.val=val;
                return;
            }
            curN=curN.next;
        }


        til.next=newArray[index];

        newArray[index]=til;

        useSize++;

        array=newArray;
    }

    /**
     * 查找该节点
     * @param key 需要查找的数据
     * @return 返回该数据的节点
     */
    public V get(K key) {
        if (isEmpty()) return null;

        int k=key.hashCode();
        int index = k % array.length;
        Node<K,V> cur=array[index];
        while (cur != null) {
            if (cur.key.equals(key)) {
                return cur.val;
            }
            cur=cur.next;
        }

        return null;
    }

    /**
     * 查找是否该节点
     * @param key 需要查找的数据
     * @return 返回是否找到
     */

    public   boolean contains(K key) {
        if (isEmpty()) return false;

        int k=key.hashCode();
        int index=k % array.length;



        Node<K,V> cur=array[index];

        while (cur != null) {
            if (cur.val.equals(key)) {
                return true;
            }
            cur=cur.next;
        }



        return false;
    }



    public boolean remove(K key) {
        if (isEmpty()) return false;

        int k=key.hashCode();
        int index = k % array.length;

        Node<K,V> cur = array[index];

        Node<K,V> node = cur;

        if (cur.key==key) {

            array[index]=cur.next;
            return true;
        }
        while (cur != null) {
            if (cur.key.equals(key)) {
                node.next = cur.next;
                useSize--;
                return true;
            }
            node = cur;
            cur = cur.next;
        }

        return false;
    }

    /**
     * 判断是否满
     * @return 返回结果
     */
    private boolean isFull() {
        return (useSize*1.0/array.length) >= 0.75;
    }

    /**
     * 判断是否为空
     * @return 返回结果
     */


    private boolean isEmpty() {
        return useSize==0;
    }
}
public class TestKVHash {
    public static void main(String[] args) {
        KVHashBucket<String,String> kvhb=new KVHashBucket<>();
        kvhb.put("钟大帅哥","喜欢美女!");
        kvhb.put("郭大男神","喜欢拉比!");
        kvhb.put("刘大少爷","喜欢花钱!");

    }


}

在这里插入图片描述

具体的实现 流程三部曲

  1. 首先创建一个 Node 类的节点

  2. 然后创建一个 Node类型的数组来存储

  3. 对利用 key 进行hashcode寻找到索引值, 根据索引操作链表 进行 增删查改

鱼式疯言

上述流程,小编只 强调三点

  1. 负载因子一旦达到 0.75 就相当于 满了, 就需要 扩容

  2. 扩容的过程中, 需要将 旧表转移到新表 中,不可以只是扩容而不转移, 否则数据会集中在原数组中, 而不会分散到新扩扩容的数组空间中。

  3. 如果添加时,遇到 相同的key 时, 只需要修改 原先 value现有的 valuekey 无须变动 即可。

    其他小编认为问题不大,小伙伴们可以自己先 操练操练 哦, 如果有不清楚的地方, 欢迎评论区留言哦 。💖 💖 💖

总结

  • hashset : 对于Hashset 来说主要是运用 Hashset 实现Set的相关的方法 来达到 判断数据是否重复进行去重操作的目的

  • HashMap : 对于 hashMap 实现 Map 接口, 达到对于 键值对之间的关联 , 已经对于 键的唯一性 所包含 值的可重复性 查找操作。

  • 哈希桶的实现: 利用数组和泛型来理解 哈希函数的底层实现 , 并注意实现过程中 负载因子的更新 以及背后的细节。

如果觉得小编写的还不错的咱可支持 三连 下 (定有回访哦) , 不妥当的咱请评论区 指正

希望我的文章能给各位宝子们带来哪怕一点点的收获就是 小编创作 的最大 动力 💖 💖 💖

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2157714.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

97、prometheus之yaml文件

命令回顾 [rootmaster01 ~]# kubectl explain ingressKIND: Ingress VERSION: networking.k8s.io/v1DESCRIPTION:Ingress is a collection of rules that allow inbound connections to reachthe endpoints defined by a backend. An Ingress can be configured to givese…

【超详细】基于YOLOv8训练无人机视角Visdrone2019数据集

主要内容如下&#xff1a; 1、Visdrone2019数据集介绍 2、下载、制作YOLO格式训练集 3、模型训练及预测 4、Onnxruntime推理 运行环境&#xff1a;Python3.8&#xff08;要求>3.8&#xff09;&#xff0c;torch1.12.0cu113&#xff08;要求>1.8&#xff09;&#xff0c…

网站建设中,sitemap是什么,有什么作用

在网站建设中&#xff0c;Sitemap&#xff08;站点地图&#xff09;是一种文件&#xff0c;通常采用txt或XML格式&#xff0c;它列出了网站中的网页、视频或其他文件的相关信息。Sitemap的主要作用是帮助搜索引擎更高效地抓取和索引网站内容。 以下是Sitemap的具体作用&#x…

ABAP 学习t-code DWDM

ABAP 学习t-code DWDM &#xff0c;里面有很多例子展示&#xff0c;且能看到源代码

【第十四章:Sentosa_DSML社区版-机器学习之时间序列】

目录 【第十四章&#xff1a;Sentosa_DSML社区版-机器学习时间序列】 14.1 ARIMAX 14.2 ARIMA 14.3 HoltWinters 14.4 一次指数平滑预测 14.5 二次指数平滑预测 【第十四章&#xff1a;Sentosa_DSML社区版-机器学习时间序列】 14.1 ARIMAX 1.算子介绍 考虑其他序列对一…

云计算第四阶段---CLOUD Day7---Day8

CLOUD 07 一、Dockerfile详细解析 指令说明FROM指定基础镜像&#xff08;唯一&#xff09;RUN在容器内执行命令&#xff0c;可以写多条ADD把文件拷贝到容器内&#xff0c;如果文件是 tar.xx 格式&#xff0c;会自动解压COPY把文件拷贝到容器内&#xff0c;不会自动解压ENV设置…

双十一快来了!什么值得买?分享五款高品质好物~

双十一大促再次拉开帷幕&#xff0c;面对众多优惠是否感到选择困难&#xff1f;为此&#xff0c;我们精心筛选了一系列适合数字生活的好物&#xff0c;旨在帮助每一位朋友都能轻松找到心仪之选。这份推荐清单&#xff0c;不仅实用而且性价比高&#xff0c;是您双十一购物的不二…

C++入门基础知识82(实例)——实例7【 判断一个数是奇数还是偶数】

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于C 实例 【判断一个数是奇数还是偶数】相…

【JavaEE初阶】文件IO(上)

欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;欢迎指出~ 目录 路径 绝对路径 相对路径 文件类型 文件的操作 File类 文件系统操作 创建文件,获取路径 删除文件 列出所有路径 路径修改 创建目录 mkdir和mkdirs 服务器领域,机械…

win系统接入google_auth实现动态密码,加强保护

开源代码地址&#xff1a;windows动态密码: 针对win服务器进行的动态密码管控&#xff0c;需要配合谷歌的身份认证APP使用 (gitee.com) 为什么要搞个动态密码呢&#xff1f; 首先云服务器启用了远程访问&#xff0c;虽然更换了端口以及初始用户名&#xff0c;不过还是是不是被…

go的结构体、方法、接口

结构体&#xff1a; 结构体&#xff1a;不同类型数据集合 结构体成员是由一系列的成员变量构成&#xff0c;这些成员变量也被称为“字段” 先声明一下我们的结构体&#xff1a; type Person struct {name stringage intsex string } 定义结构体法1&#xff1a; var p1 P…

老程序员的数字游戏开发笔记(三) —— Godot出你的第一个2D游戏(一篇文章完整演绎Godot制作2D游戏的全部细节)

忽略代码&#xff0c;忽略素材&#xff0c;忽略逻辑&#xff01; 游戏的精髓是人性与思想&#xff0c;我一篇一篇地制作&#xff0c;不想动手的小伙伴看一看就可以&#xff0c;感受一下也不错&#xff0c;我们是有目的性的&#xff0c;这一切都是为今后的AI融合打基础&#xf…

详解CORDIC算法以及Verilog实现并且调用Xilinx CORDIC IP核进行验证

系列文章目录 文章目录 系列文章目录一、什么是CORDIC算法&#xff1f;二、CORDIC算法原理推导三、CORDIC模式3.1 旋转模式3.2 向量模式 四、Verilog实现CORDIC4.1 判断象限4.2 定义角度表4.3 迭代公式 五、仿真验证5.1 matlab打印各角度的正余弦值5.2 Verilog仿真结果观察 六、…

大模型学习方向不知道的,看完这篇学习思路好清晰!!

入门大模型并没有想象中复杂&#xff0c;尤其对于普通程序员&#xff0c;建议采用从外到内的学习路径。下面我们通过几个步骤来探索如何系统学习大模型&#xff1a; 1️⃣初步理解应用场景与人才需求 大模型的核心应用涵盖了智能体&#xff08;AI Agent&#xff09;、微调&…

NodeFormer:一种用于节点分类的可扩展图结构学习 Transformer

人工智能咨询培训老师叶梓 转载标明出处 现有的神经网络&#xff08;GNNs&#xff09;在处理大规模图数据时面临着一些挑战&#xff0c;如过度平滑、异质性、长距离依赖处理、边缘不完整性等问题&#xff0c;尤其是当输入图完全缺失时。为了解决这些问题&#xff0c;上海交通大…

RK3588NPU驱动版本升级至0.9.6教程

RK3588NPU驱动版本升级至0.9.6教程 1、下载RK3588NPU驱动2、修改NPU驱动源码2.0 修改MONITOR_TPYE_DEV写错问题2.1 解决缺少函数rockchip_uninit_opp_table问题2.2 解决缺少函数vm_flags_set、vm_flag_clear的问题2.3 内核编译成功2.4 重新构建系统 3、注意事项4、其他问题处理…

故障诊断 | 基于双路神经网络的滚动轴承故障诊断

故障诊断 | 基于双路神经网络的滚动轴承故障诊断 目录 故障诊断 | 基于双路神经网络的滚动轴承故障诊断效果一览基本介绍程序设计参考资料效果一览 基本介绍 基于双路神经网络的滚动轴承故障诊断 融合了原始振动信号 和 二维信号时频图像的多输入(多通道)故障诊断方法 单路和双…

【原创】java+springboot+mysql党员教育网系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…

【Linux】常用指令【更详细,带实操】

Linux全套讲解系列&#xff0c;参考视频-B站韩顺平&#xff0c;本文的讲解更为详细 目录 一、文件目录指令 1、cd【change directory】指令 ​ 2、mkdir【make dir..】指令​ 3、cp【copy】指令 ​ 4、rm【remove】指令 5、mv【move】指令 6、cat指令和more指令 7、less和…

【爬虫工具】小红书评论高级采集软件

用python开发的爬虫采集工具【爬小红书搜索评论软件】&#xff0c;支持根据关键词采集评论。 思路&#xff1a;笔记关键词->笔记链接->评论 软件界面&#xff1a; 完整文章、详细了解&#xff1a; https://mp.weixin.qq.com/s/C_TuChFwh8Vw76hTGX679Q 好用的软件一起分…