哈希表(散列表)捋一捋

2023-11-03 04:41
文章标签 哈希 列表 一捋

本文主要是介绍哈希表(散列表)捋一捋,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

散列表(Hash table)通过将关键码映射到表中的某个位置来存储元素,然后根据关键码用同样的方式进行直接访问

散列表


理想的搜索方法是可以不经过任何比较,一次直接从表中得到要搜索的元素。如果构造一种存储结构,使元素的存储位置与它的关键码之间建立一个确定的对应函数关系Hash(),那么每个元素关键码与结构中的一个唯一的存储位置相对应:

  • Address = Hash(Key)

在插入时,根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放。在搜索时,对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键码相等,则搜索成功。该方式即散列方法(Hash Method),在散列方法中使用的转换函数叫散列函数(Hash function),构造出来的结构叫散列表(Hash Table)。

散列函数

  • 散列函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值域必须在0~m-1之间。
  • 散列函数计算出来的地址应能均匀分布在整个地址空间中。
  • 散列函数应该简单,计算快。

直接定址法

取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B。
优点:简单、均匀
缺点:需要事先知道关键字的分布情况
适合查找比较小且连续的情况。

除留余数法

设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数。
哈希函数为:Hash(key) = key % p p<=m,将关键码转换成哈希地址。
为什么要取质数(素数)呢?减小哈希冲突发生的概率

如果N=13,                          比如N=12, 
g=4, f(g,x)=g*x mod N,则          g=4, f(g,x)=g*x mod N 
4*1 mod N = 4                        4*1 mod N = 4 
4*2 mod N = 8                        4*2 mod N = 8 
4*3 mod N = 0                        4*3 mod N = 12 
4*4 mod N = 4                        4*4 mod N = 3 
4*5 mod N = 8                        4*5 mod N = 7 
4*6 mod N = 0                        4*6 mod N = 11 
4*7 mod N = 4                        4*7 mod N = 2 
4*8 mod N = 8                        4*8 mod N = 6 
4*9 mod N = 0                        4*9 mod N = 10 
4*10 mod N = 4                       4*10 mod N = 1 
4*11 mod N = 8                       4*11 mod N = 5 
4*12 mod N = 9 

数字分析法

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

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

平方取中法

假设关键字是1234,那么它的平方就是1522756,再抽取中间的3位就是227作为散列地址;再比如关键字是4321,那么它的平方就是18671041,抽取中间的3位就可以是671或者710用作散列地址。
平方取中法比较适合:不知道关键字的分布,而位数又不是很大的情况。

折叠法

折叠法是将关键字从左到右分割成位数相等的几部分(注意:最后一部分位数不够时可以短些),然后将这几部分叠加起来。有两种叠加方法:

  • 位移法:把各部分的最后一位对齐相加
  • 分界法:各部分不折断,沿各部分的分界来回折叠,然后对齐相加,将相加的结果当做散列地址。

假定关键码为:key = 23938587841,若存储空间限定3位,则划线结果为每段三位:
239 | 385 | 878 | 41
把超出地址位数的最高位删去,仅保留3位。
这里写图片描述

随机数法

选择一个随机函数,取关键字的随机函数值为它的哈希地址,即H(key) = random(key),其中random为随机数函数,通常应用于关键字长度不等时采用此法。

散列冲突

对于两个数据元素的关键字Ki和Kj(i != j),有Ki != Kj(i != j),但HashFun(Ki)== HashFun(Kj),将该种现象称为哈希冲突或哈希碰撞。把具有不同关键码而具有相同哈希地址的数据元素称为“同义词”,由同义词引起的冲突称为同义词冲突。

处理冲突的闭散列方法

闭散列也叫开地址法。
设散列表的编址为0到m-1,当添加关键码key时通过散列函数hash(key)计算key的存放位置,但在存放时发现这个桶已经被另一个keyx占据了,即发生哈希冲突。如果表未被装满,表示在给定的范围内必然还有空位置,则可以把key存放到表中“下一个”空位中。
简而言之:一旦发生冲突,就去寻找下一个空的散列表地址,只要散列表足够大,空的散列地址总能找到。

线性探查

设给出一组元素,它们的关键码为:37,25,14,36,49,68,57,11,散列表为HT[12],表的大小m =12,假设采用Hash(x) = x % p; // (p = 11) 11是最接近m的质数,就有:
Hash(37) = 4 Hash(25) = 3 Hash(14) = 3 Hash(36) = 3
Hash(49) = 5 Hash(68) = 2 Hash(57) = 2 Hash(11) = 0
这里写图片描述

散列情况统计:

要散列关键码3725143649685711
初始桶号43335220
冲突桶号--3,43,4,55,6-2,3,4,5,6,7-
最后存入桶号43567280
探查次数11343171
二次探查

使用二次探查法,在表中寻找“下一个”空位置的公式为:
Hi = (H0 + i^2)%m, Hi = (H0 - i^2)%m, i = 1,2,3…,(m-1)/2
H0是通过散列函数Hash(x)对元素的关键码x进行计算得到的位置,m是表的大小。
假设数组的关键码为37,25,14,36,49,68,57,11,假设取m=19,这样可设定为HT[19],采用散列函数
Hash(x) = x % 19
Hash(37)=18 Hash(25)=6 Hash(14)=14 Hash(36)=17
Hash(49)=11 Hash(68)=11 Hash(57)=0 Hash(11)=11
这里写图片描述

散列情况统计:

要散列关键码3725143649685711
初始桶号18614171111011
冲突桶号-----11-11,12
最后存入桶号18614171112010
探查次数11111213
双散列法

使用双散列方法,需要两个散列函数。第一个散列函数Hash()按关键码key计算其所在的位置H0 =Hash(key)。一旦发生冲突,利用第二个散列函数ReHash()计算该key到达“下一个”桶的位移,它的取值与key的值有关,要求它的取值应该是小于地址空间大小TableSize,且与TableSize互质的正整
数。
若设表的长度为m = TableSize,则在表中寻找“下一个”桶的公式为:
j = H0 = Hash(key),p = ReHash(key); j = (j+p)%m;p是小于m且与m互质的整数。

处理冲突的开散列方法

开散列法又叫链地址法(开链法)。
开散列法首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点组成一个向量,因此,向量的元素个数与可能的桶数一致。
设元素的关键码为37,25,14,36,49,68,57,11,散列表为HT[12],表的大小为12,散列函数为Hash(x)= x % 11
Hash(37)=4 Hash(25)=3 Hash(14)=3 Hash(36)=3
Hash(49)=5 Hash(68)=2 Hash(57)=2 Hash(11)=0
这里写图片描述

这篇关于哈希表(散列表)捋一捋的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/335664

相关文章

哈希leetcode-1

目录 1前言 2.例题  2.1两数之和 2.2判断是否互为字符重排 2.3存在重复元素1 2.4存在重复元素2 2.5字母异位词分组 1前言 哈希表主要是适合于快速查找某个元素(O(1)) 当我们要频繁的查找某个元素,第一哈希表O(1),第二,二分O(log n) 一般可以分为语言自带的容器哈希和用数组模拟的简易哈希。 最简单的比如数组模拟字符存储,只要开26个c

usaco 1.3 Prime Cryptarithm(简单哈希表暴搜剪枝)

思路: 1. 用一个 hash[ ] 数组存放输入的数字,令 hash[ tmp ]=1 。 2. 一个自定义函数 check( ) ,检查各位是否为输入的数字。 3. 暴搜。第一行数从 100到999,第二行数从 10到99。 4. 剪枝。 代码: /*ID: who jayLANG: C++TASK: crypt1*/#include<stdio.h>bool h

c++的初始化列表与const成员

初始化列表与const成员 const成员 使用const修饰的类、结构、联合的成员变量,在类对象创建完成前一定要初始化。 不能在构造函数中初始化const成员,因为执行构造函数时,类对象已经创建完成,只有类对象创建完成才能调用成员函数,构造函数虽然特殊但也是成员函数。 在定义const成员时进行初始化,该语法只有在C11语法标准下才支持。 初始化列表 在构造函数小括号后面,主要用于给

Spring+MyBatis+jeasyui 功能树列表

java代码@EnablePaging@RequestMapping(value = "/queryFunctionList.html")@ResponseBodypublic Map<String, Object> queryFunctionList() {String parentId = "";List<FunctionDisplay> tables = query(parent

哈希表的底层实现(1)---C++版

目录 哈希表的基本原理 哈希表的优点 哈希表的缺点 应用场景 闭散列法 开散列法 开放定值法Open Addressing——线性探测的模拟实现 超大重点部分评析 链地址法Separate Chaining——哈希桶的模拟实现 哈希表(Hash Table)是一种数据结构,它通过将键(Key)映射到值(Value)的方式来实现快速的数据存储与查找。哈希表的核心概念是哈希

哈希表的封装和位图

文章目录 2 封装2.1 基础框架2.2 迭代器(1)2.3 迭代器(2) 3. 位图3.1 问题引入3.2 左移和右移?3.3 位图的实现3.4 位图的题目3.5 位图的应用 2 封装 2.1 基础框架 文章 有了前面map和set封装的经验,容易写出下面的代码 // UnorderedSet.h#pragma once#include "HashTable.h"

【408数据结构】散列 (哈希)知识点集合复习考点题目

苏泽  “弃工从研”的路上很孤独,于是我记下了些许笔记相伴,希望能够帮助到大家    知识点 1. 散列查找 散列查找是一种高效的查找方法,它通过散列函数将关键字映射到数组的一个位置,从而实现快速查找。这种方法的时间复杂度平均为(

PHP: 深入了解一致性哈希

前言 随着memcache、redis以及其它一些内存K/V数据库的流行,一致性哈希也越来越被开发者所了解。因为这些内存K/V数据库大多不提供分布式支持(本文以redis为例),所以如果要提供多台redis server来提供服务的话,就需要解决如何将数据分散到redis server,并且在增减redis server时如何最大化的不令数据重新分布,这将是本文讨论的范畴。 取模算法 取模运

哈希表题总结

哈希表题总结 hot100两数之和字母异位词分组最长连续序列 hot100 两数之和 题目链接: 1.两数之和 代码: class Solution {public int[] twoSum(int[] nums, int target) {Map<Integer,Integer> map = new HashMap<>();int n = nums.length;for

【吊打面试官系列-Redis面试题】说说 Redis 哈希槽的概念?

大家好,我是锋哥。今天分享关于 【说说 Redis 哈希槽的概念?】面试题,希望对大家有帮助; 说说 Redis 哈希槽的概念? Redis 集群没有使用一致性 hash,而是引入了哈希槽的概念,Redis 集群有 16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽, 集群的每个节点负责一部分 hash 槽。