返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++数据结构哈希表详解
  • 170
分享到

C++数据结构哈希表详解

2024-04-02 19:04:59 170人浏览 八月长安
摘要

目录实现散列函数开散列方法闭散列方法(开地址方法)删除*实现 哈希表,即散列表,可以快速地存储和查询记录。理想哈希表的存储和查询时间都是 O(1)。 本《资料》中哈希表分以下几部分:

实现

哈希表,即散列表,可以快速地存储和查询记录。理想哈希表的存储和查询时间都是 O(1)。

本《资料》中哈希表分以下几部分:散列函数、存储和查找时的元素定位、存储、查找。删除操作因为不常用,所以只给出思想,不给出代码。

根据实际情况,可选择不同的散列方法。

以下代码假设哈希表不会溢出。

// N表示哈希表长度,是一个素数,M表示额外空间的大小,empty代表“没有元素”。
const int N=9997, M=10000, empty=-1;
int a[N];
void init() // 初始化哈希表
{
memset(a,empty,sizeof(a)); // 注意,只有empty等于0或-1时才可以这样做!
memset(bucket,empty,sizeof(bucket));
memset(first,0,sizeof(first));
}
inline int h(int); // 散列函数
int *locate(int, bool); // 用于存储和查找的定位函数,并返回对应位置。
// 如果用于存储,则第二个参数为true,否则为false①。
void save(int x) // 存储数据
{
int *p = locate(x, true);
if (p!=NULL) *p=x;
}
bool isexist(int x) // 查找数据
{
int *p = locate(x,false);
return (p!=NULL && *p==x);
}

散列函数

为了达到快速存储和查找的目的,就必须在记录的存储位置和它的关键字之间建立一个确定的对应关系 h。

这个关系 h 叫做哈希函数。

哈希表存取方便但存储时容易冲突:即不同的关键字可以对应同一哈希地址。如何确定哈希函数和解决冲突是关键。以下是几种常见的哈希函数的构造方法:

1. 取余数法:h(x) = x%p(p≤N,且最好是素数)

2. 直接定址法:h(x)=x 或 h(x)=a*x+b

3. 数字分析法:取关键字的若干数位(如中间两位数)组成哈希地址。

4. 平方取中法:关键字平方后取中间几位数组成哈希地址。

5. 折叠法:将关键数字分割成位数相同的几部分(最后一部分的位数可以不同)然后取几部分的叠加和(舍去进位)作为哈希地址。

6. 伪随机数法:事先产生一个随机数序列 r[],然后令 h(x)=r[x]。

设计哈希函数时,要注意

对关键码值的分布并不了解——希望选择的散列函数在关键码范围内能够产生一个大致平均的关键码值随机分布,同时避免明显的聚集可能性,如对关键码值的高位或低位敏感的散列函数。

对关键码值的分布有所了解——应该使用一个依赖于分布的散列函数,避免把一组相关的关键码值映射到散列表的同一个槽中。

开散列方法

哈希表中难免会发生冲突。使用开散列方法可以解决这个问题。常用操作方法是“拉链法”,即相同的地址的关键字值均链入对应的链表中。

如果散列函数很差,就容易形成长长的链表,从而影响查找的效率。

下面是用“拉链法”处理冲突时的定位函数:

int size=-1;
struct node {int v; node * next;} *first[N], mem[M];
#define NEW(p) p=&mem[++size]; p->next=NULL
int * locate(int x, bool ins=false)
{
int p=h(x);
if (a[p]==x && !ins) return &a[p];
// 处理冲突
node *q = first[p];
if (ins)
if (q==NULL)
{
NEW(q);
first[p]=q;
return &q->v;
}
else
{
while (q->next!=NULL) q=q->next;
node *r; NEW(r);
q->next=r;
return &r->v;
}
else
while (q!=NULL)
{
if (q->v == x) return &q->v;
q=q->next;
}
return NULL;
}

闭散列方法(开地址方法)

处理冲突的另一种方法是为该关键字的记录找到另一个“空”的哈希地址。在处理中可能得到一个地址序列 g(i)(i=1,2,…,k;0≤g(i)≤n-1),即在处理冲突时若得到的另一个哈希地址 g(1)仍发生冲突,再

求下一地址 g(2),若仍冲突,再求 g(3)……怎样得到 g(i)呢?

溢出桶法:设一个溢出桶,不管得到的哈希地址如何,一旦发生冲突,都填入溢出桶。

再哈希法:使用另外一种哈希函数来定位。

线性探查:g(i)=(h(x)+di) % N,其中 h(x)为哈希函数,N 为哈希表长,di 为增量序列。

1. 线性探测再散列:di=1,2,3,…,m-1

2. 二次探测再散列:

3. 伪随机探测序列:事先产生一个随机数序列 random[],令 di=random[i]。

下面是用溢出桶处理冲突时的定位函数:

int bucket[M], top=-1; // 用于闭散列方法(溢出桶)
int * locate(int x, bool ins=false)
{
int p=h(x);
if (a[p]==x && !ins) // 在查找模式下碰到了所需的元素
return &a[p];
else if (ins)
{
if (a[p]==empty) // 可以插入
return &a[p];
else // 处理冲突
return &bucket[++top];
}
else // 到溢出桶中寻找元素
for (int i=0; i<=top; i++)
if (bucket[i]==x) return &bucket[i];
return NULL;
}

下面是用线性探查处理冲突的定位函数,当然,它也可以用于再哈希法处理冲突

inline int g(int p, int i) {return (p+i)%N;} // 根据需要来设计
int * locate(int x, bool ins=false)
{
int p=h(x);
int p2, c=0;
if (a[p]==x && !ins)
return &a[p];
else if (ins)
{
do
{
p2 = g(p, c++);
} while (a[p2]!=empty);
return &a[p2];
} else {
do
{
p2 = g(p, c++);
} while (a[p2]!=x && a[p2]!=empty);
if (a[p2]==x) return &a[p2];
}
return NULL;
}

闭散列方法的优点是节省空间。不过,无论是溢出桶,还是线性探查,都会在寻址过程中浪费时间。线性

探查的探查序列如果太长,就会使一些其他元素被迫散列在其他位置,从而影响了其他元素的查找效率。

删除*

如果使用开散列方法,那么可以直接删除元素。然而,使用闭散列方法,是不可以直接删除元素的。假如

直接删除,很有可能会影响其他元素的查找。

在这种情况下,有两种删除方法:一种是交换法,另一种是标记法。

交换法:在删除某元素时,不要立刻把它清除。按照线性探查函数继续寻找,直到没有数值为止。将遇到

的最后一个数值与它交换。当然,交换之前还要进行类似的操作,可谓“牵一发而动全身”。

标记法:开一个标记数组 flag[]。如果第 i 个元素被删除了,就将 flag[i]设为 true。

1. 插入元素时,如果所在位置有标记,就把元素放到这里,并把标记清除。

2. 查找元素时,如果经过标记,就跳过去继续查找。

3. 为了哈希表的效率,应该定期清理表中的标记(或重新散列所有元素)。

到此这篇关于C++数据结构哈希表详解的文章就介绍到这了,更多相关C++哈希表内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++数据结构哈希表详解

本文链接: https://lsjlt.com/news/164654.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C++数据结构哈希表详解
    目录实现散列函数开散列方法闭散列方法(开地址方法)删除*实现 哈希表,即散列表,可以快速地存储和查询记录。理想哈希表的存储和查询时间都是 O(1)。 本《资料》中哈希表分以下几部分:...
    99+
    2024-04-02
  • C语言数据结构哈希表详解
    #include <stdio.h> #include <stdlib.h> #include <string.h> // 哈...
    99+
    2024-04-02
  • 数据结构之—哈希表
    目录 一、哈希表的概念 1.前言 2.概念 二、哈希函数:将任意一个key值映射成整数 1.哈希函数最常用的方法:取模 2.哈希函数设计原则 3.比较对象相等时,hashCode与equals关系 4.MD5:一般给字符串进行hash运算 ...
    99+
    2023-09-07
    散列表 数据结构 java 哈希表
  • 数据结构Typescript之哈希表实现详解
    目录哈希表的结构特点面向对象方法封装哈希表哈希冲突构造函数基本单元:键值对主体:哈希表增加键值对获取键值删除键值对哈希表的结构特点 相比链表繁杂的遍历处理,哈希表的作用是存储无固定...
    99+
    2023-01-30
    Typescript数据结构哈希表 Typescript数据结构
  • C++数据结构之哈希表的实现
    目录哈希表概念散列函数直接定址法除留余数法平方取中法哈希冲突线性探测二次探测链地址法哈希表的实现闭散列开散列哈希表概念 二叉搜索树具有对数时间的表现,但这样的表现建立在一个假设上:输...
    99+
    2023-03-11
    C++数据结构 哈希表 C++哈希表 C++数据结构
  • C语言数据结构哈希表是什么
    这篇文章将为大家详细讲解有关C语言数据结构哈希表是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。#include <stdio.h>#include <stdli...
    99+
    2023-06-29
  • C++数据结构之哈希表如何实现
    本篇内容主要讲解“C++数据结构之哈希表如何实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++数据结构之哈希表如何实现”吧!哈希表概念二叉搜索树具有对数时间的表现,但这样的表现建立在一个假...
    99+
    2023-07-05
  • Redis 哈希Hash底层数据结构详解
    目录1. Redis 底层数据结构2. hashtable3. redisDb 与 redisObject4. ziplist5. linkedlist6. quicklist1. ...
    99+
    2022-11-13
    redis中hash的底层 Redis底层数据结构 Redis中Hash数据结构的底层结构
  • Redis之常用数据结构哈希表
    目录1.哈希冲突2.链式哈希3.rehash4.渐进式 rehash5.rehash 触发条件哈希表是一种保存键值对(key-value)的数据结构 哈希表优点在于,它能以 O(1) 的复杂度快速查询数据。 怎么做到的呢...
    99+
    2023-04-11
    Redis常用数据结构-哈希表 数据结构之哈希表 Redis哈希表
  • Java数据结构哈希算法之哈希桶方式解决哈希冲突
    一. 实现形式一(键值对只能为整数) 我们可以先实现一个比较简单的哈希表,使用java中解决哈希冲突的方法,即哈希桶(开散列)方式实现,其中注意: 可以使用内部类方式定义节...
    99+
    2024-04-02
  • Java深入了解数据结构之哈希表篇
    目录1,概念2,冲突-避免3,冲突-避免-哈希函数设计4,冲突-避免-负载因子调节5,冲突-解决-闭散列①线性探测②二次探测6,冲突-解决-开散列/哈希桶7,完整代码1,概念 顺序结...
    99+
    2024-04-02
  • 【数据结构】 | java中 哈希表及其冲突解决
    🎗️ 博客新人,希望大家一起加油进步 🎗️ 乾坤未定,你我皆黑马 目录 1、哈希表概念2、冲突 - 概念3、冲突 - 避免 -哈希函数设计4、冲突 - 避免 -负载因子调节5、冲突 - 解决5....
    99+
    2023-08-24
    数据结构 java 散列表 哈希表 哈希
  • TypeScript基础数据结构哈希表HashTable教程
    目录前言1. 哈希表介绍和特性2. 哈希表的一些概念3. 地址冲突解决方案3.1 方案一:链地址法3.2 方案二:开放地址法4. 哈希函数代码实现5. 哈希表封装5.1 整体框架 v...
    99+
    2023-02-05
    TypeScript 数据结构HashTable TypeScript 哈希表
  • Redis常用数据结构哈希表是什么
    这篇文章主要介绍“Redis常用数据结构哈希表是什么”,在日常操作中,相信很多人在Redis常用数据结构哈希表是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Redis常用数据结构哈希表是什么”的疑惑有所...
    99+
    2023-07-06
  • 带你了解Java数据结构和算法之哈希表
    目录1、哈希函数的引入①、把数字相加②、幂的连乘2、冲突3、开放地址法①、线性探测②、装填因子③、二次探测④、再哈希法4、链地址法5、桶6、总结1、哈希函数的引入 大家都用过字典,字...
    99+
    2024-04-02
  • Python篇——数据结构与算法(第六部分:哈希表)
      目录 1、直接寻址表 2、直接寻址表缺点 3、哈希 4、哈希表 5、解决哈希冲突 6、拉链法 7、常见哈希函数 8、哈希表的实现 8.1迭代器iter()和__iter__ 8.2str()和repr() 8.3代码实现哈希表 8.4哈...
    99+
    2023-09-10
    python 数据结构 算法 哈希算法
  • 详解JavaScript实现哈希表
    目录一、哈希表原理二、哈希表的概念三、哈希化冲突问题1、链地址法2、开放地址法四、哈希函数的实现五、封装哈希表六、哈希表操作1、插入&修改操作2、获取操作3、删除操作4、判断...
    99+
    2024-04-02
  • Java数据结构之实现哈希表的分离链接法
    哈希表的分离链接法 原理 Hash Table可以看作是一种特殊的数组。他的原理基本上跟数组相同,给他一个数据,经过自己设置的哈希函数变换得到一个位置,并在这个位置当中放置该数据。哦...
    99+
    2024-04-02
  • Java数据结构中实现哈希表的分离链接法
    这篇文章主要介绍“Java数据结构中实现哈希表的分离链接法”,在日常操作中,相信很多人在Java数据结构中实现哈希表的分离链接法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java数据结构中实现哈希表的分离...
    99+
    2023-06-20
  • 哈希表(散列表)原理详解
    哈希表(散列表)是一种常见的数据结构,其原理是通过哈希函数将键映射到一个固定大小的数组索引上,以实现高效的数据存储和检索操作。下面是...
    99+
    2023-08-24
    哈希表
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作