哈希表,设计哈希集合,
哈希表是一种数据结构,它使用哈希函数组织数据,以支持快速插入和搜索
哈希表的原理
1.当我们插入一个新的键时,哈希函数将决定该键应该分配到哪个桶中,并将该键存储在相应的桶中;
2.当我们想要搜索一个键时,哈希表将使用相同的哈希函数来查找对应的桶,并只在特定的桶中进行搜索。
插入
当我们用y=x%5作为哈希函数时,
当插入key0 时 key0就放到 bucket0中
1987和2就放到了bucket2中
24就放到了bucket4中
搜索
如果我们搜索 1987,我们将使用相同的哈希函数将1987 映射到 2。因此我们在桶 2 中搜索,我们在那个桶中成功找到了 1987。
如果我们搜索 23,将映射 23 到 3,并在桶 3 中搜索。我们发现 23 不在桶 3 中,这意味着 23 不在哈希表中。
设计哈希表的关键
在上面的y=x%5散列函数中,我们可以看出 x是键值,y是分配桶的索引,
散列函数将取决于键值的范围和桶的数量。
哈希函数的设计是一个开放的问题。其思想是尽可能将键分配到桶中,理想情况下,完美的哈希函数将是键和桶之间的一对一映射。然而,在大多数情况下,哈希函数并不完美,它***需要在桶的数量和桶的容量之间进行权衡***。最好是每个桶里里面的数量能够大致差不多。
题目1
不使用任何内建的哈希表库设计一个哈希集合具体地说,你的设计应该包含以下的功能add(value):向哈希集合中插入一个值。
contains(value) :返回哈希集合中是否存在这个值。
remove(value):将给定值从哈希集合中删除。如果哈希集合中没有这个值,什么也不做。注意:所有的值都在 [0, 1000000]的范围内。操作的总数目在[1, 10000]范围内。不要使用内建的哈希集合库。
package com.youyou;/*** leetcood中* 执行用时 :33 ms, 在所有 java 提交中击败了81.40% 的用户* 内存消耗 :60 MB, 在所有 java 提交中击败了77.66%的用户** 所有的值都在 [0, 1000000]的范围内。* 操作的总数目在[1, 10000]范围内。* 不要使用内建的哈希集合库* 思路用双维数组 以y=key/bucketSize作为冲突*/
public class MyHashSet {int bucketSize=10000;int size=100;int [][]array=new int[100][10000];boolean flag=false;public MyHashSet() {}public void add(int key) {if(key==0){flag=true;return;}key=key-1;int bucket1=key/bucketSize;int bucket2=key%bucketSize;array[bucket1][bucket2]=key+1;}public void remove(int key) {if(key==0){flag=false;return;}key=key-1;int bucket1=key/bucketSize;int bucket2=key%bucketSize;array[bucket1][bucket2]=0;}/** Returns true if this set contains the specified element */public boolean contains(int key) {if(key==0){return flag;}key=key-1;int bucket1=key/bucketSize;int bucket2=key%bucketSize;return key+1==array[bucket1][bucket2];}}
/*** 别人的解题思路* 执行用时 :41 ms, 在所有 java 提交中击败了75.36% 的用户* 内存消耗 :52.8 MB, 在所有 java 提交中击败了95.39%的用户* 内存上已经很好了* 数组加双向链表,y = x % length 作为哈希函数*/public class MyHashSet2 {class Node{int val;Node prev, next;Node (int val) {this.val = val;}}private int length = 100;private Node[] data = new Node[length];/** Initialize your data structure here. */public MyHashSet2() {}public void add(int key) {int index = key % length;Node curr = data[index];if (curr == null) {Node node = new Node(key);data[index] = node;return;}while(true) {if (curr.val == key) {return;}if(curr.next == null) {Node node = new Node(key);node.prev = curr;curr.next = node;return;} else {curr = curr.next;}}}public void remove(int key) {int index = key % length;Node curr = data[index];if (curr != null && curr.val == key) {Node next = curr.next;if (next != null) {next.prev = null;}data[index] = next;return;}while(curr != null) {if (curr.val == key) {Node next = curr.next;Node prev = curr.prev;if (next != null) {next.prev = prev;}if (prev != null) {prev.next = next;}return;}curr = curr.next;}}/** Returns true if this set contains the specified element */public boolean contains(int key) {int index = key % length;Node curr = data[index];while(curr != null) {if (curr.val == key) {return true;}curr = curr.next;}return false;}
}
这个方法太叼了
/** Initialize your data structure here. 执行用时 :24 ms, 在所有 java 提交中击败了96.34% 的用户内存消耗 :54 MB, 在所有 java 提交中击败了95.04%的用户*/class MyHashSet {/** Initialize your data structure here. */boolean[] map = new boolean[1000005];public MyHashSet() {}public void add(int key) {map[key] = true;}public void remove(int key) {map[key] = false;}/** Returns true if this set contains the specified element */public boolean contains(int key) {return map[key] == true;}
}
不使用任何内建的哈希表库设计一个哈希映射
具体地说,你的设计应该包含以下的功能
put(key, value):向哈希映射中插入(键,值)的数值对。如果键对应的值已经存在,更新这个值。
get(key):返回给定的键所对应的值,如果映射中不包含这个键,返回-1。
remove(key):如果映射中存在这个键,删除这个数值对。所有的值都在 [1, 1000000]的范围内。
操作的总数目在[1, 10000]范围内。
不要使用内建的哈希库。
package com.youyou;/***所有的值都在 [1, 1000000]的范围内。*操作的总数目在[1, 10000]范围内。*不要使用内建的哈希库。* 按照上面的node方法自己写了一个 不知道为什么通不过。。。。* 感觉没有什么问题*/
public class MyHashMap {class MapNode{int key;int value;MapNode pre;MapNode next;public MapNode(int key, int value) {this.key = key;this.value = value;}public int getKey() {return key;}public void setKey(int key) {this.key = key;}public int getValue() {return value;}public void setValue(int value) {this.value = value;}public MapNode getPre() {return pre;}public void setPre(MapNode pre) {this.pre = pre;}public MapNode getNext() {return next;}public void setNext(MapNode next) {this.next = next;}}MapNode [] nodes=new MapNode[100];public MyHashMap() {}/** value will always be non-negative. */public void put(int key, int value) {int index=key%100;MapNode curr=nodes[index];if (curr==null){curr=new MapNode(key,value);nodes[index]=curr;return;}while (curr!=null){if (curr.getKey()==key){curr.setValue(value);return;}if (curr.getNext()==null){MapNode next=new MapNode(key,value);curr.setNext(next);next.setPre(curr);return;}curr=curr.next;}}/** Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key */public int get(int key) {int index=key%100;MapNode curr=nodes[index];if (curr==null){return -1;}while (curr!=null){if (curr.getKey()==key){return curr.getValue();}curr=curr.next;}return -1;}/** Removes the mapping of the specified value key if this map contains a mapping for the key */public void remove(int key) {int index=key%100;MapNode curr=nodes[index];if (curr==null){return;}while (curr!=null){if (curr.getKey()==key){MapNode pre=curr.getPre();MapNode next=curr.getNext();if (pre!=null){pre.setNext(next);}//这部分有问题 如果删除第一个节点,并且有后续节点,需要将next设置为第一个节点if (next!=null){next.setPre(pre);}if (pre==null&&next==null){nodes[index]=null;}//找了大半个小时,终于找到了问题所在,需要添加下面一份代码if (pre==null&&next!=null){nodes[index]=next;}return;}curr=curr.next;}}
}
复杂度分析
当桶的大小足够小时,桶的数量足够多时,插入和搜索的时间复杂度都是 O(1)
但在最坏的情况下,桶大小的最大值将为 N。插入时时间复杂度为 O(1),搜索时为 O(N)。
哈希表,设计哈希集合,相关推荐
- LeetCode哈希表(哈希集合,哈希映射)
文章目录 哈希表 1.原理 2.复杂度分析 题目&推荐列表 哈希集合的应用 0.常用解题模板 1.lc217 存在重复元素 2.lc136 只出现一次的数字 3.快乐数 哈希映射的应用 0.常 ...
- 除留余数法构造哈希表_哈希表算法原理
基本概念 哈希表(Hash Table)是一种根据关键字直接访问内存存储位置的数据结构.通过哈希表,数据元素的存放位置和数据元素的关键字之间建立起某种对应关系,建立这种对应关系的函数称为哈希函数. 哈 ...
- 哈希表及哈希表查找相关概念(转)
1. 哈希表的概念 对于动态查找表而言,1) 表长不确定:2)在设计查找表时,只知道关键字所属范围,而不知道确切的关键字.因此,一般情况需建立一个函数关系,以f(key)作为关键字为key的录在表中的 ...
- ds哈希查找—二次探测再散列_大白话之哈希表和哈希算法
哈希表概念 哈希表(散列表),是基于关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列函数(哈希函数 ...
- 大白话之哈希表和哈希算法
哈希表概念 哈希表(散列表),是基于关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列函数(哈希函数 ...
- 【哈希】关于哈希表和哈希函数的理解与应用
0.概述 哈希,或者说散列,在教科书上写的都比较详细,通常包括的内容有散列的方法,散列冲突的解决等.本文暂且不表这些基础知识,更多的重点在于哈希的一些应用和题目,对于哈希表.哈希函数从来没有学习过或者 ...
- 哈希表及哈希函数研究综述
哈希表及哈希函数研究综述 摘要 随着信息化水平的不断提高,数据已经取代计算成为了信息计算的中心,对存储的需求不断提高信息量呈现爆炸式增长趋势,存储已经成为急需提高的瓶颈.哈希表作为海量信息存储的有效方 ...
- [算法入门笔记] 9. 哈希表与哈希函数
文章目录 1. 哈希表与哈希函数的实现 2. 设计RandomPool结构 3. bitmap 3.1 概述 3.2 常用操作 3.2.1 存储数据 3.2.2 添加操作 3.2.3 删除操作 3.2 ...
- 【数据结构】哈希表、哈希值计算分析
哈希表.哈希值计算分析 哈希表完整代码 引出哈希表 哈希表(Hash Table) 哈希冲突(Hash Collision) JDK1.8的哈希冲突解决方案 哈希函数 如何生成 key 的哈希值 In ...
- 哈希表(哈希函数和处理哈希冲突)_20230528
哈希表(哈希函数和处理哈希冲突) 前言 关于哈希表的主题的小记原计划5月23日完成,由于本人新冠阳性,身体发烧乏力,周末感觉身体状况稍加恢复,赶紧打开电脑把本文完成,特别秉承"写是为了更好地 ...
最新文章
- 【Flutter】如何写一个Flutter自动打包成iOS代码模块的脚本
- python及pip中常用命令,经常总结
- submit按钮html,html的两种提交按钮submit和button
- git 常用别名设置
- raspberry pi_通过串行蓝牙从Raspberry Pi传感器单元发送数据
- 《虚拟化技术原理与实现》读书笔记之前序
- 后台模板 开源_3个开源样板网页设计模板
- 【华为云技术分享】“敏捷+ DevOps”先行,效能提升助推企业升级
- javascript面试题(一)
- LVS (Linux虚拟服务器)模型及算法
- 十、Shell脚本编程
- python连接mysql代码_Python连接MySQL及基本操作代码
- 3. 内存控制器与SDRAM
- 试题管理小能手,免费下载单机软件-题库管家
- 为啥俺要写博客--凭什么?
- 【计算广告】基本概念及RTB/RTA投放策略介绍
- 大功率mos管怎么测量好坏,如何用万用表判断mos管的好坏?够全面!
- 自学Java年薪20万的学习方法,大佬教你如何去学
- java 山洞过火车 java_Java多线程之生产者消费者模型
- application-dev.yml、application-test.yml、application-prod.yml的区别
热门文章
- 【量化笔记】移动均线
- c语言实训报告 需求分析,软件需求实验报告2(软件功能描述与确认)
- linux reboot故障
- 打造私人搜书系统之系统设计
- Dynamics CRM 365零基础入门学习(一)Dynamics介绍以及开发工具配置
- 机器人——人类的终极进化
- growup怎么读_欧路词典|英汉-汉英词典 grow up是什么意思_grow up的中文解释和发音_grow up的翻译_grow up怎么读...
- MATLAB控制有效数字
- 【C#进阶3-7】C# Socket通讯
- 经营养生理疗馆要注意什么问题?