哈希表是一种数据结构,它使用哈希函数组织数据,以支持快速插入和搜索

哈希表的原理

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)。

哈希表,设计哈希集合,相关推荐

  1. LeetCode哈希表(哈希集合,哈希映射)

    文章目录 哈希表 1.原理 2.复杂度分析 题目&推荐列表 哈希集合的应用 0.常用解题模板 1.lc217 存在重复元素 2.lc136 只出现一次的数字 3.快乐数 哈希映射的应用 0.常 ...

  2. 除留余数法构造哈希表_哈希表算法原理

    基本概念 哈希表(Hash Table)是一种根据关键字直接访问内存存储位置的数据结构.通过哈希表,数据元素的存放位置和数据元素的关键字之间建立起某种对应关系,建立这种对应关系的函数称为哈希函数. 哈 ...

  3. 哈希表及哈希表查找相关概念(转)

    1. 哈希表的概念 对于动态查找表而言,1) 表长不确定:2)在设计查找表时,只知道关键字所属范围,而不知道确切的关键字.因此,一般情况需建立一个函数关系,以f(key)作为关键字为key的录在表中的 ...

  4. ds哈希查找—二次探测再散列_大白话之哈希表和哈希算法

    哈希表概念 哈希表(散列表),是基于关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列函数(哈希函数 ...

  5. 大白话之哈希表和哈希算法

    哈希表概念 哈希表(散列表),是基于关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列函数(哈希函数 ...

  6. 【哈希】关于哈希表和哈希函数的理解与应用

    0.概述 哈希,或者说散列,在教科书上写的都比较详细,通常包括的内容有散列的方法,散列冲突的解决等.本文暂且不表这些基础知识,更多的重点在于哈希的一些应用和题目,对于哈希表.哈希函数从来没有学习过或者 ...

  7. 哈希表及哈希函数研究综述

    哈希表及哈希函数研究综述 摘要 随着信息化水平的不断提高,数据已经取代计算成为了信息计算的中心,对存储的需求不断提高信息量呈现爆炸式增长趋势,存储已经成为急需提高的瓶颈.哈希表作为海量信息存储的有效方 ...

  8. [算法入门笔记] 9. 哈希表与哈希函数

    文章目录 1. 哈希表与哈希函数的实现 2. 设计RandomPool结构 3. bitmap 3.1 概述 3.2 常用操作 3.2.1 存储数据 3.2.2 添加操作 3.2.3 删除操作 3.2 ...

  9. 【数据结构】哈希表、哈希值计算分析

    哈希表.哈希值计算分析 哈希表完整代码 引出哈希表 哈希表(Hash Table) 哈希冲突(Hash Collision) JDK1.8的哈希冲突解决方案 哈希函数 如何生成 key 的哈希值 In ...

  10. 哈希表(哈希函数和处理哈希冲突)_20230528

    哈希表(哈希函数和处理哈希冲突) 前言 关于哈希表的主题的小记原计划5月23日完成,由于本人新冠阳性,身体发烧乏力,周末感觉身体状况稍加恢复,赶紧打开电脑把本文完成,特别秉承"写是为了更好地 ...

最新文章

  1. 【Flutter】如何写一个Flutter自动打包成iOS代码模块的脚本
  2. python及pip中常用命令,经常总结
  3. submit按钮html,html的两种提交按钮submit和button
  4. git 常用别名设置
  5. raspberry pi_通过串行蓝牙从Raspberry Pi传感器单元发送数据
  6. 《虚拟化技术原理与实现》读书笔记之前序
  7. 后台模板 开源_3个开源样板网页设计模板
  8. 【华为云技术分享】“敏捷+ DevOps”先行,效能提升助推企业升级
  9. javascript面试题(一)
  10. LVS (Linux虚拟服务器)模型及算法
  11. 十、Shell脚本编程
  12. python连接mysql代码_Python连接MySQL及基本操作代码
  13. 3. 内存控制器与SDRAM
  14. 试题管理小能手,免费下载单机软件-题库管家
  15. 为啥俺要写博客--凭什么?
  16. 【计算广告】基本概念及RTB/RTA投放策略介绍
  17. 大功率mos管怎么测量好坏,如何用万用表判断mos管的好坏?够全面!
  18. 自学Java年薪20万的学习方法,大佬教你如何去学
  19. java 山洞过火车 java_Java多线程之生产者消费者模型
  20. application-dev.yml、application-test.yml、application-prod.yml的区别

热门文章

  1. 【量化笔记】移动均线
  2. c语言实训报告 需求分析,软件需求实验报告2(软件功能描述与确认)
  3. linux reboot故障
  4. 打造私人搜书系统之系统设计
  5. Dynamics CRM 365零基础入门学习(一)Dynamics介绍以及开发工具配置
  6. 机器人——人类的终极进化
  7. growup怎么读_欧路词典|英汉-汉英词典 grow up是什么意思_grow up的中文解释和发音_grow up的翻译_grow up怎么读...
  8. MATLAB控制有效数字
  9. 【C#进阶3-7】C# Socket通讯
  10. 经营养生理疗馆要注意什么问题?