数据结构——散列表

参考书籍:

  • 《数据结构与抽象:Java语言描述》 第四版

一、背景知识

  • 散列(hashing):是仅利用项的查找键,无需查找就可确定其下标的一项技术
  • 散列表(hash table):数组
  • 散列索引(hash index):下标
  • 散列函数(hash function):根据查找键得到元素在散列表中的整数下标
    • 查找键映射(map)或散列(hash)到下标
  • 散列函数使用hashCode()方法从查找键来计算散列码(hash code),然后将散列码压缩为散列表的地址。
    • 散列码:c;
    • 散列表的位置个数:n;(大于2的素数)
    • c%n 在0~n-1之间
    • c%n 是有n个位置的散列表的理想下标
  • 对象不equals,散列码就不同。
  • 冲突(collision):多个查找键映射到散列表中的同一个位置
  • 冲突解决方案(collision resolution):
    • 1、开放地址法
      • (1)线性探查(linear probing):检查散列表中的连续位置,从原始散列地址开始,每次的增量为1,直到找到下一个可用的位置
        • 出现的问题:基本聚集(primary clustering),即散列表中一组组(簇,cluster)连续的位置被占用
        • 优点:能够到达散列表的每个位置
      • (2)二次探查(quadratic probing):从最初的散列地址 k 开始,每次的增量为j^{2}(j\geq 0),检查地址为k+j^{2}(j\geq 0)的位置。
        • 如果探查序列到达散列表的表尾,它会绕回到表的开头。越到序列的后面距离增量会越大
        • 出现的问题:通过检查散列表中最初的散列地址加上j^{2}(j\geq 0)的位置,避免了基本聚集,但可能会导致二级聚集(增加了探查序列的长度)
      • (3)双散列(double hashing):检查散列表中最初的散列地址加上由第二个散列函数定义的增量的位置
        • 优点:避免了基本聚集和二级聚集
    • 2、拉链法
      • 桶(bucket):每个位置可以表示多个值,多用链式结构,因为可以给桶按需分配内存
      • 散列表的每个位置都是一个个链式桶,先散列查找键,然后在链式桶里查找键-值对。如果允许重复键,就把新项添加到链头,否则遍历链式桶,添加到链尾。
      • 改变了散列表的结构
  • 散列表:
    • 时间复杂度O(1)

二、(Hash Table) 

老东西,现在不咋用了

三、哈希映射(Hash Map)

//哈希映射常用方法:
Map<T,T> map=new HashMap<>();//创建一个哈希映射
map.clear();//清空哈希映射
map.containsKey(key);//是否包括元素key,返回boolean值
map.containsValue(value);//是否包括元素value,返回boolean值
map.get(key);//返回键key对应的值value
map.isEmpty();//哈希映射是否为空,返回boolean值
map.put(key,value);//把键值对存入哈希映射
map.remove(key);//移除key这对键值对
map.size();//获取哈希映射的大小
map.getOrDefault(key,value);//如果map中包含key,就获取对应的值,否则返回value

哈希集合的遍历方式:

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;public class Test {public static void main(String[] args) {HashMap<String, String> hashMap = new HashMap<>();hashMap.put("1","value1");hashMap.put("2","value2");hashMap.put("3","value3");hashMap.put("4","value4");hashMap.put("5","value5");hashMap.put("6","value6");/***  第一种遍历方式,采用for遍历key值,然后通过key去获取hashmap中的数据*/for (String key:hashMap.keySet()) {System.out.println("key: " + key + " value: " + hashMap.get(key));}/*** 第二种遍历方式,采用Iterator 把hashmap中的数据放到迭代器中,然后用while循环把迭代器中的数据都读出来*/Iterator iterator = hashMap.entrySet().iterator();while(iterator.hasNext()) {Map.Entry<String, String> entry=(Map.Entry<String, String>) iterator.next();System.out.println("Key: "+entry.getKey()+" Value: "+entry.getValue());}/*** 第三种遍历方式,采用for循环遍历hashmap中的数据,使用方便,但是数据量小时好用,如果数据量大的话非常消耗性能*/for(Map.Entry<String, String> entry: hashMap.entrySet()) {System.out.println("Key: "+ entry.getKey()+ " Value: "+entry.getValue());}}
}

三、  哈希集合(Hash Set)

//哈希集合常用方法:
Set<T> set=new HashSet<>();//创建一个T类型的哈希集合
set.add(e);//添加元素
set.clear();//清空哈希集合
set.contains(e);//哈希集合中是否包含元素e,返回boolean值
set.isEmpty();//哈希集合中是否为空,返回boolean值
set.iterator();//返回一个迭代器
set.remove(e);//删除元素e
set.size();//获取哈希集合的大小
set.toArray();//返回一个包含哈希集合所有元素的数组

HashTableHashMapHashSet
实现了接口Map实现了接口Map实现了接口Collection
存储键值对存储键值对仅存储对象(元素)
线程安全线程不安全线程不安全
不允许键或值为null,且不保证元素顺序允许键和值为null,但不保证元素顺序,且键不可重复允许值为null,但不保证元素顺序,且元素不可重复

四、例题

1、两数之和

方法一:双重for循环

class Solution {public int[] twoSum(int[] nums, int target) {int[] arr=new int[2];//把结果存入数组中返回for(int i=0;i<nums.length-1;i++){for(int j=i+1;j<nums.length;j++){if(nums[i]+nums[j]==target){arr[0]=i;arr[1]=j;break;}}}return arr;}
}

方法二:哈希表

class Solution {public int[] twoSum(int[] nums, int target) {int[] arr=new int[2];Map<Integer,Integer> ht=new HashMap<>();//创建一个哈希表for(int i=0;i<nums.length;i++){if(ht.containsKey(target-nums[i])){arr[0]=i;arr[1]=ht.get(target-nums[i]);//键break;}ht.put(nums[i],i);//哈希表的键:数组元素;值:数组元素下标}return arr;}}
/**
思路:
1、在哈希表中查找target-x
2、如果哈希表中不存在target-x,再将x插入哈希表中,即可保证x不会和自己匹配*/

进一步优化:(去掉数组后,降低了时间复杂度)

class Solution {public int[] twoSum(int[] nums, int target) {Map<Integer,Integer> ht=new HashMap<>();//创建一个哈希表for(int i=0;i<nums.length;i++){if(ht.containsKey(target-nums[i])){return new int[]{i,ht.get(target-nums[i])};}ht.put(nums[i],i);//哈希表的键:数组元素;值:数组元素下标}return new int[0];}}
/**
思路:
1、在哈希表中查找target-x
2、如果哈希表中不存在target-x,再将x插入哈希表中,即可保证x不会和自己匹配*/

2、字母异位词分组

 方法一:哈希表

class Solution {public List<List<String>> groupAnagrams(String[] strs) {List<List<String>> list1=new ArrayList<>();Map<String,List<String>> hashtable=new HashMap<>();//遍历数组,存下标进哈希表for(int i=0;i<strs.length;i++){//对单词进行重排序char[] c=strs[i].toCharArray();Arrays.sort(c);String s=new String(c);//String s=c.toString();if(!hashtable.containsKey(s)){//哈希表中未出现这种字母组合List<String> list3=new ArrayList<>();list3.add(strs[i]);hashtable.put(s,list3);}else{//哈希表中已有这种字母组合,直接添加单词进去,更新list3hashtable.get(s).add(strs[i]);//相当于list3.add(strs[i]);}}//遍历哈希表,存单词进链表for(String key:hashtable.keySet()){list1.add(hashtable.get(key));}return list1;}
}
/**
思路:
把单词按字母顺序重新排序后,存入哈希表中,当键
遍历哈希表,取出值(一条条链表list3)存入链表list1中返回*/

简洁化代码:

class Solution {public List<List<String>> groupAnagrams(String[] strs) {Map<String, List<String>> map = new HashMap<String, List<String>>();for (String str : strs) {//将排序之后的字符串作为哈希表的键char[] array = str.toCharArray();Arrays.sort(array);String key = new String(array);//如果哈希表中的key存在,就调用map.get(key)方法,返回值 //如果不存在,就返回new ArrayList<String>(),创建新链表List<String> list = map.getOrDefault(key, new ArrayList<String>());list.add(str);map.put(key, list);}//把哈希表里的值取出存入新链表返回return new ArrayList<List<String>>(map.values());}
}
//哈希表的键为一组字母异位词的标志,哈希表的值为一组字母异位词列表。

3、最长连续序列

 方法一:普通遍历

class Solution {public int longestConsecutive(int[] nums) {if(nums.length==0){return 0;}Arrays.sort(nums);//对原数组进行排序int len=1;//连续序列长度int m=1;//最大值 if(nums.length>1){for(int i=0;i<nums.length-1;i++){if(nums[i+1]-nums[i]==1){//元素是连续len++;//长度加一m=Math.max(m,len);//维护一个最大值 }else if(nums[i+1]-nums[i]>1){//元素不连续len=1;//连续序列长度重置为0,继续搜寻下一组连续序列}    }}return m;}
}
/**
思路:
1、对原数组进行排序
2、遍历原数组,维护一个序列长度的最大值 */

方法二:哈希表 

考察了hashset的contains()方法查找元素和其元素的无序性

class Solution {public int longestConsecutive(int[] nums) {Set<Integer> num_set = new HashSet<Integer>();for (int num : nums) {//用哈希表存储数组元素,去重(哈希集合不能存储相同的元素)num_set.add(num);}int longestStreak = 0;//最长序列长度for (int num : num_set) {//遍历哈希表if (!num_set.contains(num - 1)) {//当前值不存在前驱,要么它是连续序列中的第一个元素,要么它不在连续序列,跳过int currentNum = num;int currentStreak = 1;while (num_set.contains(currentNum + 1)) {//当前值存在前驱,进入内层循环,去匹配该组连续序列的数,currentNum += 1;currentStreak += 1;}longestStreak = Math.max(longestStreak, currentStreak);//维护一个最大值 }}return longestStreak;}
}

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

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

相关文章

Windos操作系统下的Zookeeper安装图文教程

凯哥已经准备好最新版本3.9.1且已经配置好了。既获取到配置好的。 获取到凯哥准备的安装后&#xff0c;只需要修改一下配置。将解压包解压后&#xff0c;找到conf文件&#xff0c;里面有个zoo.cfg配置文件。如下图&#xff1a; 下载后conf文件夹内容 打开zoo.cfg配置文件后&a…

手把手教你如何白瓢七个月阿里云云服务器

白嫖他不爽吗&#xff1f; 手把手带你白嫖七个月云服务器&#xff0c;要注意奥&#xff0c;这里白嫖七个月需要学生认证&#xff0c;才能参与高校计划。 开搞&#xff1a; 阿里云官网  不必多说&#xff0c;直接登录&#xff0c;登录时需要用支付宝扫码&#xff0c;授权后即可…

OpenAI政变背后是科学家创始人的悲歌

OpenAI政变背后是科学家创始人的悲歌 去年11月突然推出ChatGPT震惊世界的OpenAI&#xff0c;在整整一年后以闪电解职CEO再次震惊世界。 有不少人以为这拿的是乔布斯的剧本&#xff0c;错了&#xff0c;这其实是天才科学家奋力一击的故事。 OpenAI的灵魂人物不是CEO Sam Al…

每天分享五款工具,让大家工作生活更顺心

​ 快乐不是在于拥有什么,而在于我们和别人分享什么。每天分享五款工具&#xff0c;让大家工作办公更顺心就是我最大的快乐。 1.沙盒软件——Sandboxie ​ Sandboxie是一款可以在沙盒中运行程序的软件&#xff0c;它可以保护用户的系统和数据免受恶意软件、病毒和其他威胁的影…

零基础想系统地学习金融学、量化投资、数据分析、python,需要哪些课程、书籍?有哪些证书可以考?

曾经我也是零基础小白&#xff0c;题主想走的路&#xff0c;我已经走过啦&#xff5e;作为一名CFA持证人和管理因子投资的量化策略的投资组合经理&#xff0c;我把这些年积累的干货跟大家分享。 量化投资是金融学的一部分&#xff0c;量化投资&#xff08;跟量化交易的概念有部…

鸿蒙原生应用/元服务开发-AGC分发如何配置版本信息(上)

1.配置HarmonyOS应用的“发布国家或地区”。 2.设置是否为开放式测试版本。 注意&#xff1a;HarmonyOS应用开放式测试当前仅支持手机、平板、智能手表。如开发者想发布为开放式测试版本&#xff0c;选择“是”。正式发布的版本请选择“否”。 3.在“软件版本”下点击“软件包…

《活着》思维导图

今天给大家分享的这部作品的题目叫“活着”&#xff0c;作为一个词语&#xff0c;“活着”在我们中国的语言里充满了力量&#xff0c;它的力量不是来自于喊叫&#xff0c;也不是来自于进攻&#xff0c;而是忍受&#xff0c;去忍受生命赋予我们的责任&#xff0c;去忍受现实给予…

如何用html css js 画出曲线 或者斜线;

效果图 解题思路 将图片全部定位至中心点&#xff0c;然后x轴就变动translateX &#xff0c;y轴同理&#xff1b; 这里有两个问题 浏览器&#xff1a; 以左上角为原点0&#xff0c;0 越往下y越大 数学坐标系&#xff1a;以中心点为原点0&#xff0c;0 越往下y越小&#xff1…

广东网络广播电视台《明星小主播》栏目开拍 小主持神采奕奕

近日&#xff0c;由广东网络广播电视台的《明星小主播》栏目&#xff0c;在广东广播电视台&#xff08;人民北路&#xff09;广州越秀区人民北路686号主楼五楼火热开拍&#xff0c;幕后花絮曝光。《明星小主播》栏目是一档专业少儿主持类节目&#xff0c;节目旨在培养小朋友的主…

动态库符号抢占问题分析

背景 前段时间在北汽项目中&#xff0c;遇到了一个奇怪现象&#xff0c;困扰了大家较长时间。最终在和同事的不懈努力下&#xff0c;从根因上解决了该问题&#xff0c;过程中也学习到了很多。在此&#xff0c;记录并分享&#xff0c;希望能够帮助大家。 问题描述 作为OTA服务的…

【Pytorch】Visualization of Feature Maps(1)

学习参考来自 CNN可视化Convolutional Featureshttps://github.com/wmn7/ML_Practice/blob/master/2019_05_27/filter_visualizer.ipynb 文章目录 filter 的激活值 filter 的激活值 原理&#xff1a;找一张图片&#xff0c;使得某个 layer 的 filter 的激活值最大&#xff0c…

66从零开始学Java之集合中的Collection体系

作者&#xff1a;孙玉昌&#xff0c;昵称【一一哥】&#xff0c;另外【壹壹哥】也是我哦 千锋教育高级教研员、CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者 前言 截止到今天&#xff0c;我们《从零开始学Java系列》的文章已经要到一个新的阶段了。在此之前&#xf…

【网络安全】——区块链安全和共识机制

区块链安全和共识机制 摘要&#xff1a;区块链技术作为一种分布式去中心化的技术&#xff0c;在无需第三方的情况下&#xff0c;使得未建立信任的交易双方可以达成交易。因此&#xff0c;区块链技术近年来也在金融&#xff0c;医疗&#xff0c;能源等多个行业得到了快速发展。然…

卷积、卷积图像操作和卷积神经网络

好多内容直接看书确实很难坚持&#xff0c;就比如这个卷积&#xff0c;书上的一大堆公式和图表直接把人劝退&#xff0c;我觉得一般的学习流程应该是自顶向下&#xff0c;先整体后局部&#xff0c;先把握大概再推敲细节的&#xff0c;上来就事无巨细地展示对初学者来说很痛苦。…

MAX/MSP SDK学习03:Atoms and Messages的使用

今天终于把Message消息选择器看得有点头绪了&#xff0c;主要是这个官方英文文档理解起来有点抽象。 编写IsMatchABC自定义Object&#xff0c;要求&#xff1a; ①若左入口&#xff08;入口0&#xff09;收到 "int" 型消息&#xff0c;则从出口发送数值 "888&q…

51单片机/STM32F103/STM32F407学习1_点亮LED灯

目录&#xff1a; 基础知识单片机从0实现单片机GPIO介绍 参考连接&#xff1a; 野火霸天虎教程 https://doc.embedfire.com/products/link/zh/latest/mcu/stm32/ebf_stm32f407_batianhu_v1_v2/download/stm32f407_batianhu_v1_v2.html x.1 基础知识 x.1.1 指针中的取地址&a…

数据标注:猫目标检测数据集label标签制作

对于猫十二分类数据标注部分&#xff0c;可以使用官方制作的标注软件 下载地址&#xff1a;精灵标注助手-人工智能数据集标注工具 (jinglingbiaozhu.com) 标注图片为150张猫的图片 如下&#xff1a;

java智慧校园信息管理系统源码带微信小程序

一、智慧校园的定义 智慧校园指的是以云计算和物联网为基础的智慧化的校园工作、学习和生活一体化环境。以各种应用服务系统为载体&#xff0c;将教学、科研、管理和校园生活进行充分融合&#xff0c;让校园实现无处不在的网络学习、融合创新的网络科研、透明高效的校务治理、…

适合学校或高校老师、学生学习用的网盘推荐

现代教育中&#xff0c;数字化的教学资源和家长的参与度越来越重要。然而文件传输的问题一直是学校和家长面临的一个挑战&#xff0c;网络限制、U盘病毒和文件管理不便等问题&#xff0c;都对教学质量和家校沟通造成了影响。Zoho WorkDrive企业网盘为学校还有教辅机构提供了一个…

基于单片机智能液位水位监测控制系统设计

**单片机设计介绍&#xff0c; 基于单片机智能液位水位监测控制系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的智能液位水位监测控制系统可以用来检测和控制液位的高低&#xff0c;并可以用于水泵的控制和自…