Map和Set(哈希表)

目录

map:

map说明:

Map.Entry的说明:,v>

Map 的常用方法:

演示:

注意:

TreeMap和HashMap的区别

 Set:

常见方法说明:

注意:

TreeSet和HashSet的区别 

哈希表:

冲突:

冲突-避免:

冲突-避免-负载因子调节:

冲突-解决:

冲突-解决-闭散列:

冲突-解决-开散列/哈希桶:

结语:


map:

map说明:

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

Map.Entry<K,V>的说明:

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

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

注意:Map.Entry并没有提供设置Key的方法.

Map 的常用方法:

如下图所示:

Map底层可以用Hashmap和Treemap实现,由于Hashmap的效率比较高故下面我用Hashmap来进行演示。

演示:

import java.util.Map;
import java.util.HashMap;
import java.util.Set;
public class Hashmap {
    public static void main(String[] args) {
        Map<String,Integer> map = new HashMap<>();
        map.put("aaa",3);
        map.put("bbb",3);
        System.out.println(map.get("aaa"));
        Set<Map.Entry<String,Integer>> set = map.entrySet();
        for(Map.Entry<String,Integer> entry:set){
            System.out.println("Key :"+entry.getKey() + " Value :" + entry.getValue());
        }
    }
}

entrySet是比较重要的故进行演示。

效果如下:

这里采用foreach进行遍历,可以不用直到Set的长度。

注意:

1. Map是一个接口,不能直接实例化对象,如果要实例化对象只能实例化其实现类TreeMap或者HashMap。

2. Map中存放键值对的Key是唯一的,value是可以重复的。

3. 在TreeMap中插入键值对时,key不能为空,否则就会抛NullPointerException异常,value可以为空。但 是HashMap的key和value都可以为空。

4. Map中的Key可以全部分离出来,存储到Set中来进行访问(因为Key不能重复)。

5. Map中的value可以全部分离出来,存储在Collection的任何一个子集合中(value可能有重复)。

6. Map中键值对的Key不能直接修改,value可以修改,如果要修改key,只能先将该key删除掉,然后再来进行 重新插入。

TreeMap和HashMap的区别

 Set:

Set与Map主要的不同有两点:Set是继承自Collection的接口类,Set中只存储了Key。

常见方法说明:

方法解释
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 c)将集合c中的元素添加到set中,可以达到去重的效果

演示:

public class Test1 {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        set.add("aaa");
        set.add("bbb");
        System.out.println(set.size());
        System.out.println(set.isEmpty());
        set.clear();
    }
}

效果如下:

注意:

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可以。

TreeSet和HashSet的区别 

哈希表:

概念:

顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找一个元素时,必须要经过关键 码的多次比较。顺序查找时间复杂度为O(N),平衡树中为树的高度,即O(logn ),搜索的效率取决于搜索过程中 元素的比较次数。

理想的搜索方法:可以不经过任何比较,一次直接从表中得到要搜索的元素。 如果构造一种存储结构,通过某种函 数(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快 找到该元素。

插入元素:

根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放。

搜索元素:

对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键码相等,则搜索成功。

该方式即为哈希(散列)方法,哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表(Hash Table)(或者称散列表)

冲突:

对于两个数据元素的关键字和 (i != j),有 != ,但有:Hash( ) == Hash( ),即:不同关键字通过相同哈 希哈数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。 把具有不同关键码而具有相同哈希地址的数据元素称为“同义词”。

例如:

下图的4和7就是发生了冲突。

冲突-避免:

 首先,我们需要明确一点,由于我们哈希表底层数组的容量往往是小于实际要存储的关键字的数量的,这就导致一 个问题,冲突的发生是必然的,但我们能做的应该是尽量的降低冲突率。

函数设计:

哈希函数设计原则:

(1)哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值域必须在0到m-1 之间。

(2)哈希函数计算出来的地址能均匀分布在整个空间中。

(3)哈希函数应该比较简单。

常见哈希函数:

(1)直接定制法:

取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B 优点:简单、均匀缺点:需要事先知道关 键字的分布情况使用场景:适合查找比较小且连续的情况。

(2)除留余数法:

设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,按照哈希函数: Hash(key) = key% p(p<=m),将关键码转换成哈希地址。

冲突-避免-负载因子调节:

已知哈希表中已有的关键字个数是不可变的,那我们能调整的就只有哈希表中的数组的大小。

冲突-解决:

解决哈希冲突两种常见的方法是:闭散列和开散列。

冲突-解决-闭散列:

闭散列:也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以 把key存放到冲突位置中的“下一个” 空位置中去。

寻找方法:

(1)线性探测

线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。

注意:这里的删除都是伪删除。

(2) 二次探测:

找下一个空位置的方法为: = ( + )% m, 或者: = ( - )% m。其中:i = 1,2,3…, 是通过散列函数Hash(x)对元素的关键码 key 进行计算得到的位置, m是表的大小。

冲突-解决-开散列/哈希桶:

开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子 集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中。

简单来说就是数组加链表。

如图:

开散列,可以认为是把一个在大集合中的搜索问题转化为在小集合中做搜索了。

源代码的实现:


public class HashBucket {
    static class Node{
        private int key;
        private int value;
        Node next;
        public Node(int key,int value){
            this.key = key;
            this.value = value;
        }
    }
    private Node[] array;
    private int size;
    public HashBucket(){
        array = new Node[8];
        size = 0;
    }
    private static final double LOAD_FACTOR = 0.75;
    public int put(int key,int value){
        int index = key % array.length;
        Node cur = array[index];
        for(;cur != null; cur = cur.next){
            if(cur.key == key){
                int oldValue = cur.value;
                cur.value = value;
                return oldValue;
            }
        }
        Node node = new Node(key,value);
        node.next = array[index];
        array[index] = node;
        size++;
        if(loadFactor() >= LOAD_FACTOR){
            resize();
        }
        return -1;
    }
    //重新哈希
    private void resize(){
        Node[] newArray = new Node[array.length * 2];
        for(int i = 0;i < array.length; i++){
            Node next;
            for(Node cur = array[i]; cur != null; cur = next){
                next = cur.next;
                int index = cur.key % newArray.length;
                cur.next = newArray[index];
                newArray[index] = cur;
            }
        }
        array = newArray;
    }
    private double loadFactor(){
        return size * 1.0 / array.length;
    }
    public int get(int key){
        int index = key % array.length;
        for(Node cur = array[index]; cur != null; cur = cur.next){
            if(key == cur.key){
                return cur.value;
            }
        }
        return -1;
    }

}

性能分析:

虽然哈希表一直在和冲突做斗争,但在实际使用过程中,我们认为哈希表的冲突率是不高的,冲突个数是可控的, 也就是每个桶中的链表的长度是一个常数,所以,通常意义下,我们认为哈希表的插入/删除/查找时间复杂度是 O(1) 。

结语:

其实写博客不仅仅是为了教大家,同时这也有利于我巩固自己的知识点,和一个学习的总结,由于作者水平有限,对文章有任何问题的还请指出,接受大家的批评,让我改进,如果大家有所收获的话还请不要吝啬你们的点赞收藏和关注,这可以激励我写出更加优秀的文章。

                                                 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FileZilla Server 1.8.1内网搭建

配置环境服务器服务器下载服务器配置服务器配置 Server - ConfigureServer Listeners - Port 协议设置 Protocols settingsFTP and FTP over TLS(FTPS) Rights management(权利管理)Users(用户) 客户端建立连接 配置环境 服务器处于局域网内: 客户端 < -访问- > 公网 &l…

车载软件架构 —— Adaptive AUTOSAR软件架构

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师&#xff08;Wechat&#xff1a;gongkenan2013&#xff09;。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 本就是小人物&#xff0c;输了就是输了&#…

寒假思维训练day21

今天更新一道不错的状态压缩DP题&#xff0c;顺带总结一下状态压缩DP。 摘要&#xff1a; Part1 浅谈状态压缩DP的理解 Part2 浅谈对状态机DP的理解 Part3 关于状态压缩DP的1道例题 Part1 状态压缩DP 1、状态压缩DP&#xff1a; 事物的状态可能包含多个特征&#xff0c;…

linuxqq关闭主面板后无法再次打开的问题

文章目录 前言解决方案强调一点 前言 听说QQ出了linux版&#xff0c;所以来试试。结果试试就逝世。这次记录一个关闭后没办法打开的解决办法。 解决方案 刚安装好后如果点了关闭&#xff0c;系统托盘里也没有&#xff0c;点击图标又是重新登录。当然&#xff0c;我们最简单、…

浅谈Linux环境

冯诺依曼体系结构&#xff1a; 绝大多数的计算机都遵守冯诺依曼体系结构 在冯诺依曼体系结构下各个硬件相互配合处理数据并反馈结果给用户 其中控制器和运算器统称为中央处理器&#xff08;CPU&#xff09;&#xff0c;是计算机硬件中最核心的部分&#xff0c;像人类的大脑操控…

钓鱼邮件的发送工具GUI

一.简介 本程序利用Python语言编写&#xff0c;使用Tkinter实现图形化界面&#xff0c;可使用Pyinstaller进行exe打包&#xff0c;程序主界面截图如下&#xff1a; 二.功能 1.支持腾讯企业邮、网易企业邮、阿里企业邮、自建邮服SMTP授权账号&#xff08;其他邮服&#xff0c…

【HTML】交友软件上照片的遮罩是如何做的

笑谈 我不知道大家有没有在夜深人静的时候感受到孤苦难耐&#xff0c;&#x1f436;。于是就去下了一些交友软件来排遣寂寞。可惜的是&#xff0c;有些交友软件真不够意思&#xff0c;连一些漂亮小姐姐的图片都要进行遮罩&#xff0c;完全不考虑兄弟们的感受,&#x1f620;。所…

微信小程序(四十一)wechat-http的使用

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.模块下载 2.模块的使用 在终端输入npm install wechat-http 没有安装成功vue的先看之前的一篇 微信小程序&#xff08;二十&#xff09;Vant组件库的配置- 如果按以上的成功配置出现如下报错先输入以下语句 …

知识价值2-什么是IDE?新手用哪个IDE比较好?

IDE是集成开发环境&#xff08;Integrated Development Environment&#xff09;的缩写&#xff0c;是一种软件应用程序&#xff0c;旨在提供集成的工具集&#xff0c;以方便开发人员进行软件开发。IDE通常包括代码编辑器、编译器、调试器和其他工具&#xff0c;以支持软件开发…

crack实验

资源下载 【免费】crack资源&#xff08;这玩意还要不少于11字&#xff09;资源-CSDN文库 内容 源码 这是一段简单的密码判断程序 流程 exe直接用ida开&#xff08;因该是release的exe&#xff09; 选中分支点直接按空格 此时的va地址是0010106e用动态调试软件调试&#xf…

微信小程序学习指南:从基础知识到代码展示

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

软件实例分享,宠物店兽医电子处方开单系统软件教程

软件实例分享&#xff0c;宠物店兽医电子处方开单系统软件教程 一、软件教程问答 以下教程以 佳易王宠物店兽医电子处方软件V16.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 问&#xff1a;宠物医院电子处方单子使用的纸张大小是多少&…

Screw自动生成数据库文档

Screw简介 官方地址 Screw可以根据数据库中的表自动生成HTML、Word、Markdown格式的文档。 Springboot 3.1集成 生成Springboot项目 Spring Initializr Maven依赖 <dependency><groupId>cn.smallbun.screw</groupId><artifactId>screw-core</…

GPT4:画一只小怪兽,但是不断升级

请你画一只1级的萌怪兽 请你画一只3级的萌怪兽 请你画一只5级的小怪兽 请你画一只10级的小怪兽 请你画一只50级的怪兽 请你画一只100级的怪兽 怪兽被闪电劈了一下&#xff0c;变成了一只0.1级的可爱小怪兽

JAVA-多进程开发-创建等待进程

前言 在项目中&#xff0c;为了实现“并发编程”&#xff08;同时执行多个任务&#xff09;&#xff0c;就引入了“多进程编程”&#xff0c;把一个很大的任务&#xff0c;拆分成若干个很小的任务&#xff0c;创建多个进程&#xff0c;每个进程分别负责其中的一部分任务。 这也…

(三十七)大数据实战——Solr服务的部署安装

前言 Solr是一个基于Apache Lucene的开源搜索平台&#xff0c;它提供了强大的全文搜索、分布式搜索和数据分析功能。Solr 可以用于构建高性能的搜索应用程序&#xff0c;支持从海量数据中快速检索和分析信息。Solr 使用倒排索引和先进的搜索算法&#xff0c;可实现快速而准确的…

NLP快速入门

NLP入门 课程链接&#xff1a;https://www.bilibili.com/video/BV17K4y1W7yb/?p1&vd_source3f265bbf5a1f54aab2155d9cc1250219 参考文档链接1&#xff1a;NLP知识点&#xff1a;Tokenizer分词器 - 掘金 (juejin.cn) 一、分词 分词是什么&#xff1f; 每个字母都有对应…

Codeforces Round 169 (Div. 2)C. Little Girl and Maximum Sum(差分、贪心)

文章目录 题面链接题意题解代码总结 题面 链接 C. Little Girl and Maximum Sum 题意 给q个[l,r]将所有这些区间里面的数相加和最大。 可以进行的操作是任意排列数组 题解 对出现的每个区间内的位置加上1&#xff0c;代表权值 操作完之后求一遍前缀和&#xff0c;得到每个…

《统计学简易速速上手小册》第10章:案例研究和未来趋势(2024 最新版)

文章目录 10.1 统计学成功案例分析10.1.1 基础知识10.1.2 主要案例&#xff1a;药物临床试验10.1.3 拓展案例 1&#xff1a;市场趋势分析10.1.4 拓展案例 2&#xff1a;社会行为研究 10.2 统计学的伦理考量10.2.1 基础知识10.2.2 主要案例&#xff1a;个性化医疗研究10.2.3 拓展…

生活篇——华为手机去除负一屏

华为手机去除如下图的恶心负一屏 打开华为的应用市场app 进入&#xff1a;我的-设置-国家/地区&#xff08;改为俄罗斯&#xff09;-进入智慧助手检查更新并更新智慧助手。 然后重复开始的操作&#xff0c;将地区改回中国&#xff0c;这样就没有负一屏了。