当前位置: 首页 > news >正文

数据结构从青铜到王者第十九话---Map和Set(2)

 🔥个人主页:寻星探路

🎬作者简介:Java研发方向学习者

📖个人专栏:《从青铜到王者,就差这讲数据结构!!!》、 《JAVA(SE)----如此简单!!!》、《数据库那些事!!!》

⭐️人生格言:没有人生来就会编程,但我生来倔强!!!



续接上一话

目录

一、Set 的说明

1、常见方法说明

2、TreeSet的使用案例

二、哈希表

1、概念

2、冲突-概念

3、冲突-避免

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

4.1常见的哈希函数

4.1.1直接定制法--(常用)

4.1.2除留余数法--(常用)

4.1.3平方取中法--(了解)

4.1.4折叠法--(了解)

4.1.5随机数法--(了解)

4.1.6数学分析法--(了解)

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


一、Set 的说明

Set 的官方文档https://docs.oracle.com/javase/8/docs/api/java/util/Set.html        Set与Map主要的不同有两点:Set是继承自Collection的接口类,Set中只存储了Key。

1、常见方法说明

#注:

(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的区别【HashSet我们在后面最后会讲到】

2、TreeSet的使用案例

import java.util.TreeSet;
import java.util.Iterator;
import java.util.Set;public static void TestSet(){Set<String> s = new TreeSet<>();// add(key): 如果key不存在,则插入,返回ture// 如果key存在,返回falseboolean isIn = s.add("apple");s.add("orange");s.add("peach");s.add("banana");System.out.println(s.size());System.out.println(s);isIn = s.add("apple");// add(key): key如果是空,抛出空指针异常//s.add(null);// contains(key): 如果key存在,返回true,否则返回falseSystem.out.println(s.contains("apple"));System.out.println(s.contains("watermelen"));// remove(key): key存在,删除成功返回true//              key不存在,删除失败返回false//              key为空,抛出空指针异常s.remove("apple");System.out.println(s);s.remove("watermelen");System.out.println(s);Iterator<String> it = s.iterator();while(it.hasNext()){System.out.print(it.next() + " ");}System.out.println();
}

二、哈希表

1、概念

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

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

当向该结构中:

        插入元素

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

        搜索元素

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

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

例如:数据集合{1,7,6,4,5,9};

        哈希函数设置为:hash(key) = key % capacity; capacity为存储元素底层空间总的大小。

        用该方法进行搜索不必进行多次关键码的比较,因此搜索的速度比较快

问题:按照上述哈希方式,向集合中插入元 素44,会出现什么问题?

2、冲突-概念

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

        把具有不同关键码而具有相同哈希地址的数据元素称为“同义词”。

3、冲突-避免

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

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

        引起哈希冲突的一个原因可能是:哈希函数设计不够合理

        哈希函数设计原则

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

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

                哈希函数应该比较简单

4.1常见的哈希函数

4.1.1直接定制法--(常用)

        取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B

        优点:简单、均匀

        缺点:需要事先知道关键字的分布情况

        使用场景:适合查找比较小且连续的情况

        面试题: 387. 字符串中的第一个唯一字符 - 力扣(LeetCode)

        我们可以对字符串进行两次遍历。

        在第一次遍历时,我们使用哈希映射统计出字符串中每个字符出现的次数。在第二次遍历时,我们只要遍历到了一个只出现一次的字符,那么就返回它的索引,否则在遍历结束后返回 −1。

class Solution {public int firstUniqChar(String s) {Map<Character, Integer> frequency = new HashMap<Character, Integer>();for (int i = 0; i < s.length(); ++i) {char ch = s.charAt(i);frequency.put(ch, frequency.getOrDefault(ch, 0) + 1);}for (int i = 0; i < s.length(); ++i) {if (frequency.get(s.charAt(i)) == 1) {return i;}}return -1;}
}
4.1.2除留余数法--(常用)

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

4.1.3平方取中法--(了解)

        假设关键字为1234,对它平方就是1522756,抽取中间的3位227作为哈希地址; 再比如关键字为4321,对它平方就是18671041,抽取中间的3位671(或710)作为哈希地址

        平方取中法比较适合:不知道关键字的分布,而位数又不是很大的情况

4.1.4折叠法--(了解)

        折叠法是将关键字从左到右分割成位数相等的几部分(最后一部分位数可以短些),然后将这几部分叠加求和, 并按散列表表长,取后几位作为散列地址。

        折叠法适合事先不需要知道关键字的分布,适合关键字位数比较多的情况

4.1.5随机数法--(了解)

        选择一个随机函数,取关键字的随机函数值为它的哈希地址,即H(key) = random(key),其中random为随机数函数。

        通常应用于关键字长度不等时采用此法

4.1.6数学分析法--(了解)

        设有n个d位数,每一位可能有 r 种不同的符号,这r种不同的符号在各位上出现的频率不一定相同,可能在某些位上分布比较均匀,每种符号出现的机会均等,在某些位上分布不均匀只有某几种符号经常出现。可根据散列表的大小,选择其中各种符号分布均匀的若干位作为散列地址。

例如:

        假设要存储某家公司员工登记表,如果用手机号作为关键字,那么极有可能前7位都是相同的,那么我们可以选择后面的四位作为散列地址,如果这样的抽取工作还容易出现冲突,还可以对抽取出来的数字进行反转(如1234改成4321)、右环位移(如1234改成4123)、左环移位、前两数与后两数叠加(如1234改成12+34=46)等方法。

        数字分析法通常适合处理关键字位数比较大的情况,如果事先知道关键字的分布且关键字的若干位分布较均匀的情况

#注:哈希函数设计的越精妙,产生哈希冲突的可能性就越低,但是无法避免哈希冲突

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

负载因子和冲突率的关系粗略演示

        所以当冲突率达到一个无法忍受的程度时,我们需要通过降低负载因子来变相的降低冲突率。

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

        我们会在下一话讲到如何去解决冲突!!!

        由于内容较多,会分为多篇讲解,预知后续内容,请看后续博客!!!


文章转载自:

http://NQqH0Yin.btpLL.cn
http://40ywvemY.btpLL.cn
http://xZYGufBK.btpLL.cn
http://VVHnxbAs.btpLL.cn
http://UZKwQnJZ.btpLL.cn
http://uAcTnR4W.btpLL.cn
http://RcWBYY4s.btpLL.cn
http://U9KMRpOD.btpLL.cn
http://rROsj63W.btpLL.cn
http://HtHP6ukl.btpLL.cn
http://hGcAQyJY.btpLL.cn
http://sfcbk5v6.btpLL.cn
http://MoXVSEmS.btpLL.cn
http://rv1f1F3l.btpLL.cn
http://cVV25Qco.btpLL.cn
http://hjina03H.btpLL.cn
http://uVpRrMAb.btpLL.cn
http://MoGuTUWm.btpLL.cn
http://LKHb7A7V.btpLL.cn
http://6SjH1OXZ.btpLL.cn
http://VqgD4YtL.btpLL.cn
http://TZN7GuD6.btpLL.cn
http://6s1hq1xi.btpLL.cn
http://qkJonNfk.btpLL.cn
http://ecPRSzjc.btpLL.cn
http://SoOkUmFs.btpLL.cn
http://WNmk6Hg0.btpLL.cn
http://pq3Rka21.btpLL.cn
http://CoWHUTnL.btpLL.cn
http://AOa3qVJ5.btpLL.cn
http://www.dtcms.com/a/366042.html

相关文章:

  • git之分支
  • 如何创建交换空间
  • 【音视频】视频秒播优化实践
  • 无穿戴动捕如何深度结合AI数据分析,实现精准动作评估?
  • 代码随想录刷题Day48
  • Linux 字符设备驱动框架学习记录(三)
  • 数学建模-非线性规划(NLP)
  • STM32HAL 快速入门(十七):UART 硬件结构 —— 从寄存器到数据收发流程
  • DOM常见的操作有哪些?
  • Day34 UDP套接字编程 可靠文件传输与实时双向聊天系统
  • 信号调制与解调 matlab仿真
  • 异常处理机制与debug
  • 复写零(双指针)
  • 单片机day2
  • 配置时钟分频与倍频
  • 解构复杂财务逆向业务:如何优雅地生成与管理负数单?
  • Python基础(⑥属性装饰器)
  • 你只需输入一句话,MoneyPrinterTurbo直接给你输出一个视频
  • 普通人如何用 AI 提效?5 个低门槛工具 + 3 类场景案例,让 AI 成为日常助手
  • phpstorm 操作git 另外的操作在 我的收藏
  • c#编写的应用程序调用不在同一文件夹下的DLL
  • Java继承
  • c++ zint二维码、条形码开发库
  • c++多线程(1)------创建和管理线程td::thread
  • Python数据分析与处理(二):将数据写回.mat文件的不同方法【超详细】
  • AI+法律:用ERNIE-Bot解析合同条款,识别风险点
  • 进程管理和IPC
  • 常用假设检验方法及 Python 实现
  • 多层环境室内定位系统综述总结
  • 【JavaEE】(22) Spring 事务