哈希表(散列表)

哈希表算法(闭散列表操作,开散列表操作)创建,查找,插入,删除 #include <stdio.h> #include <malloc.h> #include "stdlib.h" #include <math.h> typedef int Status; typedef int KEYTYPE; typedef struct { KEYTYPE key; }ElemType; typedef struct { ... 阅读详情

一、定义 

哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。

也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。


哈希表的做法其实很简单,就是把Key通过一个固定的算法函数既所谓的哈希函数转换成一个整型数字,然后就将该数字对数组长度进行取余,取余结果就当作数组的下标,将value存储在以该数字为下标的数组空间里。
而当使用哈希表进行查询的时候,就是再次使用哈希函数将key转换为对应的数组下标,并定位到该空间获取value,如此一来,就可以充分利用到数组的定位性能进行数据定位。

比如:有一个很大的有序数组,想要得到位于该数组第n个位置的值,它的算法复杂度为O(1)。

哈希表利用哈希函数将需要存储的内容的关键值转换为这个有序数组中的某个值,在被存储内容和有序数组之间建立了映射关系。这样,下次我们对这个值进行查找时只要使用同一个哈希函数对关键值进行转换,找到这个数组值 就可以了。


      如果还没有明白是怎么回事的话,那我们来举个例子。假设我们要做个存储结构,需要存储下来三国中的人物,以及他们的详细信息。我们用他们的名字来作为存储 的关键值,例如:刘备,曹操,孙权,关羽,张飞……等等。这个时候我们如果想用一般的方法来查找这些英雄豪杰,需要遍历整个存储空间,如果这些英雄豪杰一 共有n个,那么这时候的时间算法复杂度为O(n)。显然如果n值很大,每次想要找到某个英雄就需要比较长的时间。
      此时我们先定义一个大的有序结构数组HashValue[m],用来存放各位英雄豪杰的信息。然后编写一个哈希函数ChangeToHashValue (name),函数的具体内容就不细说了,反正这个函数会将这些做为关键值的名字转换为HashValue[m]中的某个下标值x。然后可以将英雄的信息 放进HashValue[x]中去。这样,可以将所有英雄的信息存储起来。当查询的时候再使用哈希函数ChangeToHashValue(name)得 到这个下标值,这样就很容易得到了这个英雄的信息。例如:ChangeToHashValue(刘备)为10,那么就将刘备存储到HashValue [10]里面。当查询的时候再次使用ChangeToHashValue(刘备)得到10,这个时候我们就可以很容易找到刘备的所有信息。在实际应用中如 果我们想把所有的英雄豪杰都存储进系统时,需要定义m>n。就是数组的大小要大于需要存储的信息量,所以说哈希表是一个以空间换取时间的数据结构。
      这个时候问题来了,出现了这种情况ChangeToHashValue(关羽)和ChangeToHashValue(张飞)得到的值是一样的,都是 250,我们岂不是在存储过程中会遇到麻烦,怎么安排他们二位的地方呢(总不能让二位打一架,谁赢了谁呆在那吧),这就需要一个解决冲突的方法。当遇到这 种情况时我们可以这样处理,先存储好了关羽,当张飞进入系统时会发现关羽已经是250了,那咱就加一位,251得了,这不就解决了。我们查找张飞的时候也 是,一看250不是张飞,那就加个1,就找到了。这时还存在一个问题。直接用ChangeToHashValue(赵云)为251,张飞已经早早占了他的 地方,那就再加1存到252呗。呵呵,这时我们会发现,当哈希函数冲突发生的机率很高时,可能会有一群英雄豪杰在250这个值后面扎堆排队。要命的是查找 的时候,时间算法复杂度早已不是O(1)了(所以我们说理想情况下哈希表的时间算法复杂度为O(1))。      

这就是说哈希函数的编写是哈希表的一个关键问题,会涉及到一个存储值在哈希表中的统计分布。如果哈希函数已经定义好了,冲突的解决就成为了改变系统性能的关键因素。其实还有很多种方法来解决冲突情况下的存储和查找问题,不一定非要线性向后排队,如果有好的哈希表冲突的解决方法也能很大程度上提高系统的效 率。


二、

1 基本原理
  使用一个下标范围比较大的数组来存储元素。可以设计一个函数(哈希函数, 也叫做散列函数),使得每个元素的关键字都与一个函数值(即数组下标)相对应,于是用这个数组单元来存储这个元素;也可以简单的理解为,按照关键字为每一个元素"分类",然后将这个元素存储在相应"类"所对应的地方。

  但是,不能够保证每个元素的关键字与函数值是一一对应的,因此极有可能出现对于不同的元素,却计算出了相同的函数值,这样就产生了"冲突",换句话说,就是把不同的元素分在了相同的"类"之中。后面我们将看到一种解决"冲突"的简便做法。

  总的来说,"直接定址"与"解决冲突"是哈希表的两大特点。

2 函数构造

  构造函数的常用方法(下面为了叙述简洁,设 h(k) 表示关键字为 k 的元素所对应的函数值):

  a) 除余法:

  选择一个适当的正整数 p ,令 h(k ) = k mod p 
  这里, p 如果选取的是比较大的素数,效果比较好。而且此法非常容易实现,因此是最常用的方法。

  b) 数字选择法:

  如果关键字的位数比较多,超过长整型范围而无法直接运算,可以选择其中数字分布比较均匀的若干位,所组成的新的值作为关键字或者直接作为函数值。

3 冲突处理

  线性重新散列技术易于实现且可以较好的达到目的。令数组元素个数为 S ,则当 h(k) 已经存储了元素的时候,依次探查 (h(k)+i) mod S , i=1,2,3…… ,直到找到空的存储单元为止(或者从头到尾扫描一圈仍未发现空单元,这就是哈希表已经满了,发生了错误。当然这是可以通过扩大数组范围避免的)。

4 支持运算

  哈希表支持的运算主要有:初始化(makenull)、哈希函数值的运算(h(x))、插入元素(insert)、查找元素(member)。
  设插入的元素的关键字为 x ,A 为存储的数组。
  初始化比较容易,例如
  const empty=maxlongint; // 用非常大的整数代表这个位置没有存储元素
     p=9997;      // 表的大小
  procedure makenull;
   var i:integer;
   begin
    for i:=0 to p-1 do
     A[i]:=empty;
   End;

  哈希函数值的运算根据函数的不同而变化,例如除余法的一个例子:
  function h(x:longint):Integer;
   begin
    h:= x mod p;
   end;

  我们注意到,插入和查找首先都需要对这个元素定位,即如果这个元素若存在,它应该存储在什么位置,因此加入一个定位的函数 locate 
  function locate(x:longint):integer;
   var orig,i:integer;
   begin
    orig:=h(x);
    i:=0;
    while (i<S)and(A[(orig+i)mod S]<>x)and(A[(orig+i)mod S]<>empty) do
     inc(i); 
     //当这个循环停下来时,要么找到一个空的存储单元,要么找到这个元
     //素存储的单元,要么表已经满了
    locate:=(orig+i) mod S;
   end;
  插入元素
  procedure insert(x:longint);
   var posi:integer;
   begin
    posi:=locate(x);      //定位函数的返回值
    if A[posi]=empty then A[posi]:=x
          else error; //error 即为发生了错误,当然这是可以避免的
   end; 

  查找元素是否已经在表中
  procedure member(x:longint):boolean;
    var posi:integer; 
    begin
     posi:=locate(x);
     if A[posi]=x then member:=true
             else member:=false;
    end;

  这些就是建立在哈希表上的常用基本运算。

三、应用

查找一个数组中重复最多的项 

比如[1,12,4,5,6,7,11,1,1,2,2,2,6]   这里1和2都重复了3次 

1.先排序,O(n*log(n))  然后在遍历一次O(n)

输出的是一个列表,显示的是原来列表里面的每个数出现的次数.

var _array:Array=[1,12,4,5,6,7,11,1,1,2,2,2,6];
var _total:Array=new Array();
for (var i:int=0; i<_array.length; i++) {
        _total[i]=0;
        for (var j:int=0; j<_array.length; j++) {
                if (_array[i]==_array[j]) {
                        _total[i]=_total[i]+1;
                }
        }
}
trace(_total);


2.最快的就是使用哈希表(Hash Table),复杂度为O(n)-O(1),计算为O(n),读取为O(1)

var maxid:int = 0;
for (var i:int = 0; i<=n; i++)
{
  num[a[i]]++;
  if (num[a[i]]>maxid) maxid = i;
}
trace(a[maxid]);

哈希表与散列表的原理及C++实现 哈希表(Hash Table)是一种高效的数据结构,用于存储键值对(Key-Value Pairs)。它通过哈希函数(Hash Function)将键(Key)映射到一个固定大小的数组(称为散列表)中的某个位置,从而实现快速的插入、查找和删除操作。哈希表的核心思想是通过哈希函数将键转换为数组的索引,从而直接访问对应的值。理想情况下,哈希表的插入、查找和删除操作的时间复杂度都是O(1)。哈希表是一种高效的数据结构,通过哈希函数将键映射到数组索引,从而实现快速的插入、查找和删除操作。 阅读详情

相关推荐

hash table 哈希表(散列表)

hash table ,也叫散列表。涉及到哈希函数、哈希冲突处理的问题。哈希函数是哈希表的关键,是用来从值到哈希表索引(存放位置)的映射。 比如:要存放一个学校学生的姓名,他们是Amanda, Jack, Andy, Tom, Bob, Black等等500个人。我们可以设计一个哈希表,容量为500,来存放这些学生的信息。哈希表的目的是快速访问,利用数组的随机访问性,快速的通过下表访问元素。需要

csdn_chai的博客 786

Java中HashMap集合及get()和put()的实现原理

​ HashMap集合: 1、HashMap集合基础 底层是哈希表/散列表的数据结构,是非线程安全的。在JDK8之后,如果哈希表单向链表中元素超过8个,单向链表这种数据结构会变成红黑树数据结构。当红黑树上的节点数量小于6时,会重新把红黑树变成单向链表数据结构。这种方式也是为了提高检索效率,二叉树的检索会再次缩小扫描范围。提高效率。初始化容量16.默认加载因子0.75扩容是:扩容之后的容量是原容量...

guoyuxin3的博客 3014

什么是散列表(哈希表)?

本文文末有福利,不要错过奥! 前言 假设你们班级100个同学每个人的学号是由院系-年级-班级和编号组成,例如学号为01100168表示是1系,10级1班的68号。为了快速查找到68号的成绩信息,可以建立一张表,但是不能用学号作为下标,学号的数值实在太大。因此将学号除以1100100取余,即得到编号作为该表的下标,那么,要查找学号为01100168的成绩的时候,只要直接访问表下标为68的数据即可...

守望的博客-编程珠玑 3568

Hashtable的get()和put()

jdk1.8 中hashtable的get() 首先计算key的下标,获取hashtable中的数组 找到对应下标数组,获取对应的链表 遍历俩表,判断是否有满足条件的entry,如果有,获取value对应的值返回 否则,返回为空. @SuppressWarnings("unchecked") public synchronized V get(Object key) { ...

kai3123919064的博客 6237

V2签名预装失败原因及解决方案

GOOGLE最新的GTS要求targetSdkVersion 大于30的APK必须使用V2及以上签名。 但实际在预装过程中,GTS测试会失败。 后面发现这是由于预装方式的原因造成的。原来的预装方式是使用APK,指定APK使用预签名的方式。Android.mk如下: LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := DKTest LOCAL_MODULE_CLASS := APPS LOCAL_MODULE_TAGS

zyfzhangyafei的专栏 6304

AD4030-24BBCZ详细资料 Analog Devices 模数转换器 - ADC 24-Bit, 2 MSPS, SAR ADC

AD4030-24BBCZ详细资料  Analog Devices 模数转换器 - ADC 24-Bit, 2 MSPS, SAR ADC

Chen_YYan的博客 794

数据结构与算法【Python实现】(五)哈希表

一、哈希表 哈希表是一个通过哈希函数来计算数据存储位置的数据结构,通常支持如下操作: insert(key,value):插入键值对(key,value) get(key):如果存在键为key的键值对则返回其value,否则返回空 delete(key):删除键为key的键值对 直接寻址表:key为k的元素放到k位置上 改进直接寻址表:哈希 Hashing 构建大小为m的寻址表T key为k的元素放到h(k)位置上 h(k)是个函数,将k...

hhhxykeke的博客 1261

ZYQN7000系列VxWorks驱动开发:VxWorks系统移植

文章目录ZYQN7000驱动开发:VxWorks系统移植1.硬件环境2.编译vsb和vip工程2.1修改设备树文件2.2添加调试打印组件3.选择uboot来启动VxWorks内核4.尝试在开发板上启动内核4.1 拷贝镜像和设备树至SD卡4.2开发板上电4.2.1 uboot成功启动4.2.2 启动VxWorks5.添加shell和cmd组件 ZYQN7000驱动开发:VxWorks系统移植 1.硬件环境 正点原子领航者开发板 2.编译vsb和vip工程 vsb和vip工程的编译过程可以参考之前的文章,htt

明故宫的记忆 5507

二十、哈希表的基础知识

哈希表是什么? 定义:根据设定的哈希函数H(key)和处理冲突的方法,将一组关键字映射到一个有限的连续的地址集(区间)上,并以关键字在地址集中的“像”作为记录在表中的存储位置,这种表称为哈希表,也叫作散列表,这一映射过程称为哈希造表或散列,所得的存储位置称为哈希地址或散列地址。 构造哈希表:以记录的关键字为自变量计算一个函数( 称为哈希函数)来得到该记录的存储地址并存入元素,因此在哈希表中进行查找操作时,必须计算同一个哈希函数,首先得到待查记录的存储地址,然后到相应的存储单元去获得有关信息再判定查找是否成

仁化居之安 2025

DAZ STUDIO 快速渲染技巧

DAZ STUDIO 快速渲染技巧: 本文将向您展示几个快速渲染技巧。您将学习如何使您的Daz Iray渲染和照明在Daz工作室内更快。 当你有一个大场景,这可能需要很多小时进行渲染。 但是如果你想大幅度降低渲染时间呢?这篇文章的提示应该能让你达到这个目标。 首先,我们需要弄清楚一件事——没有“完美的环境或设置”这样的东西。是因为渲染设置是高度个性化和主观性的东西,这主要取决于场景和硬件。如果你有一个功能强大的计算机,你可以允许更多的低渲染时间,反之亦然。因此,一切都取决于您尝试渲染的对象和机器。

DAZSTUDIO的博客 9650

Simscape Multiboby学习笔记1——跟着官网学Multibody

文章目录一. 引言二. Simscape Multibody自学之路三. 本教程的目录 一. 引言 最近在倒腾Matlab的动力学仿真,起因是看到有人推荐Matlab的multbody模块,一经了解之下简直惊为天人。作为一名Matlab的小粉,看到这么好用的模块简直不要太开心,之前用simulink搭飞行器的仿真模型,虽然能够仿真看到六自由度位移,毕竟不能可视化,还是很不够直观,而且simulink仿真(以及更费力的脚本文件仿真)需要精确建模,模型不精确计算也是天差地别。而Multibody在具备其他动力学

qq_30267617的博客 8241

哈希表的原理

哈希表的原理 引入哈希表 在无序数组中按照内容查找,效率低下,时间复杂度为O(n): 在有序数组中按照内容查找,可以使用折半查找,时间复杂度O(log2n): 在二叉平衡树中按照内容查找,时间复杂度O(log2n) : 在数组中按照索引查找,不进行比较和计数,直接计算得到,效率最高,时间复杂度O(1)  问题:按照内容查找,能否也不进行比较,而是通过计算得到地址,实现类似数组按照索引查询的高效率呢O(1) 有!!!哈希表来实现 前面查找方法共同特点:通过将关键字值与给定值比较,来确定位置。效率取决比较次

qq_40836864的博客 2412

USC EE450 CSCI455 CSCI571 Midterm 总结

EE450 Compter Network                1.历年Midterm考题。(更新至2017年spring,如果大家有新的资源欢迎编辑)                 google drive:https://drive.google.com/drive/folders/0B_LCDxpiiXZ1cUNReFpZZHo4NG8?usp=sharing

Small_hour 7112

哈希表(散列表)C/C++代码实现

哈希表(散列表): 1,构造散列函数 最常用的方法是除留余数法: H(key) = key%p 这个方法的关键是选取适当的p, 一般情况下,可以选p为小于表长的最大质数。例如表长m=100, 可取p=97。 2,处理冲突 选择一个 “好” 的散列函数可以在一定程度上减少冲突,但在实际应用中,很难完全避免发生冲突 1,开放地址法 (1)线性勘测法 (2)二次探测法 (3)伪随机探测法 线性探测法的优点是:只要散列表未填满,总能 找到一个不发生冲突的地址。缺点是:会产生 ”二次聚集“ 现象。而二次探测法和伪随机

Ycy的博客 1万+

手把手教你用Ollama & AnythingLLM搭建AI知识库,无需编程,跟着做就行!

本地运行大模型耗资源,需要选择较小的模型作为基础模型。在终端中运行时可能会出现 CUDA 错误,表示显存不足,导致提供的端口失效。中文支持不够完善。\3. 文中提到的技术软件工具有:Ollama、Chatbox、Open WebUI、向量数据库、嵌入模型、本地模型 Gemma、AnythingLLM。

2401_86435672的博客 1万+

【PCIe硬件】PCIe引脚PRSNT与热插拔

热插拔的基本目的是要让PCIe设备按照规定的顺序、原则,从系统中移除或插入到系统中来,并能正常的工作,且不影响系统的正常运行。事实上,PCIe“热插拔”的关键目的就是为前面面所提到的系统RAS服务的,是提升系统RAS能力的非常重要的手段!注意,这里有两个相关概念,前面我们讲的热插拔,其实是广义的“热插拔”。这里的Hot-Plug,为了方便,我们叫做PCIe热插拔,也就是我们现在及后面将要讨论的内容。

smartvxworks的博客 2807

数据结构——哈希表(散列表)

文章目录一,哈希表(散列表)概念二,哈希(散列)函数的构造哈希(散列)函数的构造原则构造方法平方取中法折叠法保留余数法三,冲突处理散列冲突的方法开放定址法1.线性探测法2.二次探测法3.随机探测法再散列函数法公共溢出区法链地址法四,代码实现1.哈希函数2.链表和哈希表的创建3.哈希表初始化3.从哈希表中根据key查找元素4.哈希表插入元素5.元素删除6.哈希表销毁 一,哈希表(散列表)概念 大话数据结构里面是这样介绍的: 散列表,又称为哈希表(Hash table),采用散列技术将记录存储在一块连续的存储空

m0_61705102的博客 1万+

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

哈希表(散列表)详解

深入理解哈希表,哈希函数的构造和解决哈希冲突的方法

不能再留遗憾了的博客 2309

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

[一篇详解哈希表]数据结构之哈希表(散列表)

✅作者简介:大家好,我是Philosophy7?让我们一起共同进步吧!🏆 📃个人主页:Philosophy7的csdn博客 🔥系列专栏: 👑哲学语录: 承认自己的无知,乃是开启智慧的大门 💖如果觉得博主的文章还不错的话,请点赞👍+收藏⭐️+留言📝支持一下博>主哦🤞 文章目录散列表简介:为什么需要散列表?哈希函数的实现哈希表的代码 散列表 简介: 散列表又可以叫做哈希表,那什么是散列表呢? 现在就让我们深入研究一下吧 是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把.

Philosophy7的博客 2405

数据结构 | 散列表(哈希表)

​ 散列表(Hash Table),也称为哈希表,是一种根据关键码值(Key value)而直接进行访问的数据结构。它通过把关键码值映射到表中一个位置来访问记录,从而加快查找速度。这个映射函数称为散列函数,存放记录的数组称为散列表。

ROBOT_a的博客 2705

散列表(Hash table哈希表)应用案例

散列表(Hash table哈希表)应用案例

qqrrjj2011的博客 1327

C++数据结构之Hash table(哈希表|散列表)

哈希表(Hash Table),也称为散列表(思考:vs平衡二叉树),是一种数据结构,它提供了通过键(key)直接访问存储的值(value)的能力。哈希表的工作原理基于哈希函数(Hash Function),该函数将输入的键映射到表中的一个位置,使得和操作都能在接近常数时间内完成(

weixin_49962210的博客 3317

散列表(哈希表)

散列表(hash table,又称哈希表),是一种数据集,其中数据项的存储方式尤其有利于将来快速的查找定位。散列表的基本思想是,首先在关键字key和存储位置p之间建立一个对应关系H,使得p = H(key),H称为哈希函数,p称为散列地址。当创建哈希表时,把关键字key的记录直接存入地址为H(key)的地址单元中;以后查找关键字为key的元素时,再利用哈希函数p = H(key)计算出该元素的散列地址p,从而达到直接存取记录的目的。

2302_77530416的博客 963

数据结构——散列表(Hash Table)(哈希表)

散列表 散列表英文是hashtable,经常被叫做Hash表,或者哈希表。 哈希表其实就是由数组演化而来的,利用的就是数组支持按照下标随机访问数据的特性,可以说散列表就是数组的一种扩展。 百度文库对散列表的解释: 根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的...

qq_42006733的博客 2016

算法设计与分析——散列表/哈希表(Hash Table)(三):散列表原理

直接寻址技术的缺点是非常明显的:如果全域U很大,则在一台标准的计算机可用内存容量中,要存储大小为∣U∣|U|∣U∣的一张表TTT也许不太实际,甚至是不可能的。还有,实际存储的关键字集合KKK相对UUU来说可能很小,使得分配给TTT的大部分空间都将浪费掉。 当存储在字典中的关键字集合KKK比所有可能的关键字的全域UUU要小许多时,散列表需要的存储空间要比直接寻址表少得多。特别地,我们能将散列表的存储需求降至Θ(∣K∣)\Theta(|K|)Θ(∣K∣),同时散列表中查找一个元素的优势仍得到保持,只需要O(1)

冯·诺依曼 1万+

哈希表(Hash Table)/散列表(Key-Value)

   目录 1. 哈希表的基本思想 2. 哈希表的相关基本概念   1.概念:   2.哈希表和哈希函数的标准定义:   1)冲突:   2)安全避免冲突的条件:   3)冲突不可能完全避免   4)影响冲突的因素 3. 哈希表的实现方法 4. 哈希表“定址”的方法   1)直接定址法   2)除法取余法   3)数字分析法   4)平方取中法   5)折叠法 5...

Lightmare625 1万+
上一篇: 数组指针 指针数组 指向数组 的区别
下一篇: var关键字
firefly_2002
博客等级 码龄14年 434粉丝 66原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值