哈希表的实现

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

1、哈希表
说明1
说明2
哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
哈希表hashtable(key,value) 就是把Key通过一个固定的算法函数既所谓的哈希函数转换成一个整型数字,然后就将该数字对数组长度进行取余,取余结果就当作数组的下标,将value存储在以该数字为下标的数组空间里。参考
1、利用链地址法实现
一个散列函数能够将键转化为数组索引。散列算法的第二步就是碰撞处理,也就是处理两个或多个键的散列值相同的情况。拉链法就是将大小为M 的数组中的每个元素指向一条链表,链表中的每个结点都存储了散列值为该元素的索引的键值对。这个方法的思想就是选择足够大的M,使得所有链表都尽可能短以保障高效的查找,否则容易退化成单链表的情况。如下图中M=5:
参考

// 哈希函数.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<memory.h>
#include<iostream>
using namespace std;

class HashTable
{
public:
	typedef struct _HashNode//哈希节点
	{
		int key;//值
		_HashNode* pNext;//指向下一个节点的值
	}HashNode;

	typedef struct _Hash
	{
		_HashNode* pElement;//数据元素的存放空间
	}_Hash;

public:
	void InitHashTable(int len);//初始化哈希表
	int Hash(int key);//计算哈希值
	void InsertData(int key);//插入数据
	HashNode* SearchTable(int key, int *addr);//查找数据
	void CreateTable(int array[], int n);//建立哈希表
	void ShowHash();//显示数据

private:
	_Hash m_hashTable;//哈希表
	int m_tableLength;//哈希表长

};

int _tmain(int argc, _TCHAR* argv[])
{
	HashTable hash;
	hash.InitHashTable(7);

	int arr[] = { 19, 1, 23, 14, 55, 68, 11, 82, 36 };
	hash.CreateTable(arr, 9);

	hash.ShowHash();

	int addr = 0;
	HashTable::_HashNode* pNode = hash.SearchTable(19, &addr);
	cout << "找到的值是:" << pNode->key <<endl<< "地址为:" << addr << endl;

	return 0;
}

void HashTable::InitHashTable(int len)
{
	m_tableLength = len;
	m_hashTable.pElement = new _HashNode[len];//开辟存放数组元素空间
	memset(m_hashTable.pElement, 0x00, sizeof(_HashNode)*len);
}

int HashTable::Hash(int key)//哈希值
{
	return key%m_tableLength;//数组元素对表长取余就是哈希值
}

void HashTable::InsertData(int key)
{
	int addr = Hash(key);//获取哈希值
	if (m_hashTable.pElement[addr].key==0)//判断是否存在哈希冲突
	{
		m_hashTable.pElement[addr].key = key;//将要插入的值放在对应的位置
	}
	else
	{
		_HashNode* pNew = new _HashNode;//新建一个节点
		pNew->key = key;//将值赋值给新节点
		pNew->pNext = m_hashTable.pElement[addr].pNext;//将新节点指向的下一个位置置为空
		m_hashTable.pElement[addr].pNext = pNew;//新节点放在上一个点的后面
	}

}

void HashTable::CreateTable(int array[], int n)//将数组的数据插在哈希表中
{
	for (int i = 0; i < n; i++)
	{
		InsertData(array[i]);
	}
}

void HashTable::ShowHash()
{
	for (int i = 0; i < m_tableLength; i++)
	{
		cout << "第" << i << ":";
		_HashNode* pNode = &(m_hashTable.pElement[i]);
		while (pNode)
		{
			cout << pNode->key << " ";
			pNode = pNode->pNext;
		}
		cout << endl;
	}
}

HashTable::HashNode* HashTable::SearchTable(int key, int* addr)
{
	*addr = Hash(key);

	_HashNode* pNode = &(m_hashTable.pElement[*addr]);

	while (pNode)
	{
		if (pNode->key==key)
		{
			return pNode;
		}
		pNode = pNode->pNext;//继续查找
	}
	return pNode;

}

2、利用开放地址法实现
这个方法的基本思想是:当发生地址冲突时,按照某种方法继续探测哈希表中的其他存储单元,直到找到空位置为止。这个过程可用下式描述:
H i ( key ) = ( H ( key )+ d i ) mod m ( i = 1,2,…… , k ( k ≤ m – 1))
其中: H ( key ) 为关键字 key 的直接哈希地址, m 为哈希表的长度, di 为每次再探测时的地址增量。
采用这种方法时,首先计算出元素的直接哈希地址 H ( key ) ,如果该存储单元已被其他元素占用,则继续查看地址为 H ( key ) + d 2 的存储单元,如此重复直至找到某个存储单元为空时,将关键字为 key 的数据元素存放到该单元。
增量 d 可以有不同的取法,并根据其取法有不同的称呼:
( 1 ) d i = 1 , 2 , 3 , …… 线性探测再散列;
( 2 ) d i = 1^2 ,- 1^2 , 2^2 ,- 2^2 , k^2, -k^2…… 二次探测再散列;
( 3 ) d i = 伪随机序列 伪随机再散列;
参考

#include"stdafx.h"
#include<iostream>
#include<memory.h>
using namespace std;

class HashTable
{
public:
	typedef struct _Hash
	{
		int *pElement;//存放数组
		int nCount;//数组元素个数
	}_Hash;
	void InitHashTable(int len);//初始化数组
	int Hash(int key);//计算函数值
	void InsertData(int key);
	void CreatHashTable(int array[], int n);
	bool SearchHash(int key, int *addr);
	void ShowHash();
private:
	_Hash hashTable;
	int TableLen;
};

int _tmain(int argc, _TCHAR* argv[])
{
	HashTable hashK;
	hashK.InitHashTable(17);

	int arr[] = { 47, 7, 29, 11, 16, 92, 22, 8, 3 };
	hashK.CreatHashTable(arr, 9);

	hashK.ShowHash();

	int addr = 0;
	bool ret = hashK.SearchHash(29, &addr);
	cout << "查找结果 : " << ret << "\t地址为 : " << addr << endl;

	return 0;
}

void HashTable::InitHashTable(int len)
{
	TableLen = len;
	hashTable.pElement = new int[len];
	hashTable.nCount = 0;

	memset(hashTable.pElement, 0x00, sizeof(int)*len);
}

int HashTable::Hash(int key)
{
	return key%TableLen;
}

void HashTable::InsertData(int key)
{
	if (hashTable.nCount>=TableLen)
	{
		return;
	}

	int addr = Hash(key);

	while (hashTable.pElement[addr]!=0)//有冲突就将余数+1再继续处理
	{
		addr = (addr + 1) % TableLen;
	}

	hashTable.pElement[addr] = key;
	hashTable.nCount++;
}

void HashTable::CreatHashTable(int array[], int n)
{
	for (int i = 0; i < n; i++)
	{
		InsertData(array[i]);
	}
}

bool HashTable::SearchHash(int key, int *addr)
{
	*addr = Hash(key);

	int nCount = 0;
	while (hashTable.pElement[*addr]!=0)
	{
		*addr = (*addr + 1) % TableLen;

		if (++nCount>TableLen)
		{
			return false;
		}
	}
	return true;
}

void HashTable::ShowHash()
{
	for (int i = 0; i < TableLen; i++)
	{
		cout << "第" << i <<" "<< hashTable.pElement[i] << endl;
	}
}
散列表/哈希表(C语言简单实现) 散列表/哈希表(C语言简单实现) 本文参考自《大话数据结构》 定义 通过某个函数f计算出记录的存储位置,而不需要通过比较,这就是一种新的存储技术——散列技术。 散列技术是在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key) 。在查找时,根据这个确定的对应关系找到给定值key的映射f(key),若查找集合中存在这个记录,则必定在f(key)的位置上。 我们把这种对应关系f称为散列函数,又称为哈希函数。按照这个思路,采用散列技术将记录存储在一块连续的存储 阅读详情

相关推荐

散列表性质与实现

原文转自:  http://blog.youkuaiyun.com/intrepyd/article/details/4359818

飞扬的青春的专栏 1295

哈希表实现(c/C++)

哈希表的c/cpp实现(链式结构线性结构)含完整代码

tyq20010606的博客 1694

HashSet和HashMap的底层实现——哈希表、散列表

java.lang  类 Object java.lang.Object int hashCode()            返回该对象的哈希码值。 boolean equals(Object obj)           指示某个其他对象是否与此对象“相等”。 一、概述 java最基本的两种数据结构

lpp1234567的专栏 7370

哈希表实现原理

Hash表实现原理

challenglistic的博客 1282

Python爬虫实战:手把手教你用Selenium绕过药监局网站的反爬机制(附完整代码)

本文详细介绍了如何使用Selenium绕过药监局网站的反爬机制,提供了一套完整的Python爬虫实战方案。通过浏览器指纹伪装、动态等待策略、会话维持技巧以及分布式采集设计,帮助开发者高效爬取药监局数据,解决政府类网站常见的反爬挑战。

weixin_42620255的博客 737

电动汽车充电设备标准化设计方案:电气原理图

80kW一体式一机一枪充电机电气原理 主电路拓扑见图1,配置1个250A直流充电连接装置,提供4个充电模块安装位置,根据充电功率需求可选配2~4个20kW充电模块。内置直流电能表和计费控制单元,实现计量计费和充电控制功能。 图1 80kW一体式一机一枪充电机主电路拓扑 ...

santirenpc的博客 1万+

详解哈希表(hashtable)实现

【代码】哈希表(hashtable)实现详解。

工匠精神coding,终生学习 643

攻击时间控制的动态逆三维制导律(源代码)

%参考文献:《攻击时间控制的动态逆三维制导律》,哈尔滨工程大学学报,2010 %编程难点:视线坐标系与参考坐标系间的转换关系 一、采用本文方法结果 二、偏航通道采用增广比例导引律

算法小站 2393

Hash哈希表原理

数组:索引固定域。 哈希表:映射对关系。 哈希表是一种数据结构,其根据关键字实现数据内容的快速查询(映射关系)。 哈希表哪些优点? 不论哈希Hash表中存储的数据量有多少,通通采用映射访问的机制一步找到目标数据,所以对于数据的增加/删除/改写,基于时间参考基准下的时间复杂度平均都是O(1),效率非常高。 哈希表实现底层码 哈希表原理:如果说每一个数据它都对应着一个固定的位置,那我们查找特定一个数据时,就可以直接查看这个数据对应的位置是否存在数据。一个形象的例子就是学生在教室中的位置,开学的时候,老师会给学

yanhaijunyan的博客 547

软件自动化测试脚本如何编写,编写自动化测试脚本的几点注意事项

我们需要自动化测试脚本的原因:1、验收测试是一项非常复杂和费力的被用来确保软件质量的环节。它的目的就是使软件能得到充分运行并且能使其符合原始需求。2、测试的目的无非就是满足了两个结果:测试通过或测试不通过。为了能实现每个测试结果,必须要明确每个测试用例。并且对于整个系统而言在合同中必须定义测试用例的失败标准,而且这个失败标准数必须是可接受的。3、测试用例的通过条件必须有一个清晰的标准,标准可以被定...

weixin_39575775的博客 2251

使用-flat.vmdk文件恢复ESXI虚拟机的vmdk文件

解决flat.vmdk文件丢失恢复问题

神秘人的博客 6772

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

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

Ycy的博客 1万+

一文掌握DrissionPage的详细使用

是一个基于 Python 的网页自动化工具,主要用于网页数据的抓取、自动化操作和测试。它结合了 Selenium 和 Requests 的优点,提供了更简洁、高效的 API,适用于各种网页自动化任务。DrissionPage 是一个功能强大且易于使用的网页自动化工具,适用于各种网页自动化任务。希望本文的 DrissionPage 的基本使用方法和一些高级功能能够帮助到你。

数据知道的博客 1万+

基于散列表(线性探查的哈希表和链式散列)的字典实现

字典的另一种表示是散列。它用一个散列函数(也称哈希函数)把字典的数对映射到一个散列表(也称哈希表)的具体位置。与跳表相比,它把操作的时间提高到渐近等于1,但最坏情况下依然是渐近等于N。但是如果经常输出所有元素或按照顺序查找元素(如查找第10个最小元素之类),跳表的执行效率将优于散列。 基于跳表的字典实现 散列函数和散列表 1.桶和起始桶 当关键字范围太大,不能用理想方法表示时,可以采用并不理想的散...

sinat_40408114的博客 1748

TenserRt平台SMOKE 3D目标检测部署完整教程:从理论到实践

本教程详细介绍了在RK3588平台上部署SMOKE 3D目标检测模型的完整流程。SMOKE是一种创新的单阶段单目3D检测方法,通过关键点估计直接预测3D目标信息,有效解决了深度信息缺失等挑战。文章从理论基础出发,解析了SMOKE的核心算法和网络架构,包括DLA-34主干网络和关键点中心化策略。同时提供了详细的Docker环境配置、模型导出到ONNX格式的实践指南,以及TensorRT引擎构建和性能优化的关键技术要点。该教程为开发者在嵌入式平台上实现高效3D目标检测提供了完整的技术参考。

LXY_LOVE36的博客 371

C#实战:从零搭建Vosk离线语音转文字系统

本文手把手教你用C#构建离线语音转文字系统,基于NAudio和Vosk实现全流程开发。首先介绍环境搭建,包括NuGet包安装和中文模型配置,强调16kHz单声道音频格式的关键性。接着详细解析音频预处理转换、Vosk模型初始化及识别过程的核心代码,提供多线程优化建议和实时识别扩展思路。文章包含80%以上代码注释,从常见问题排查到性能优化技巧,完整覆盖从"Hello World"到工业级部署的关键技术点,特别适合需要开发本地化语音识别应用的C#开发者。

墨夶的博客 752

哈希表(散列表) C++实现

文章目录哈希函数哈希函数的构造方法处理散列冲突的方法散列表性能分析散列表C++代码实现 哈希函数 哈希函数就是 关键字Key 到 值Value 的映射: Value = f(Key) Value反映的是关键字Key的存储地址。 哈希函数的构造方法 直接定址法 f(Key) = a * Key + b 例如存放不同出生年份的人口数量,出生年份是关键字,那么可以用直接定址法。 直接定址法的优点是简单均匀,也不会产生冲突;缺点是该方法适合表比较小且连续的情况,所以 该方法虽然简单但是并不常用。 数

Worthy_Wang的博客 1847

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

java实现简单的散列表(哈希表)

前情提要:众所周知,散列表(哈希表)是一种根据关键码值而直接进行访问的数据结构,即通过将关键码值映射到表中的一个位置来访问记录,以加快查找的速度。映射的函数叫散列函数,存放记录的数组叫散列表 使用java的面向对象思维来编写会很好理解:解析都在代码里 import java.util.Scanner; /** * @author Administrator * 2020-04-11-1...

weixin_44157472的博客 358

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

哈希表(散列表)的代码实现及介绍

文章目录一、哈希表(散列表)1.解释2.代码实现二、字典树(前缀树)1.简单介绍2.代码实现三、探讨学习 一、哈希表(散列表) 1.解释 这里引入百度百科的解释: 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。 也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。 给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地

GGB__的博客 583

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

C++ 哈希表实现

什么叫做哈希表?相信大家在很多地方都听过哈希表这三个字。在之前,我看到java之父余胜军装小白面试的时候,对哈希表那是侃侃而谈,非常的羡慕他对哈希表的理解,在学习哈希表过后,我发现他的难度还不一定比得上红黑树,那让我们今天来揭开哈希表的神秘面纱。哈希表跟set和map结构类似,库函数如果是unordered_set,那就是Key模型库函数如果是unordered_map,那就是Key,Value模型。表我们很容易理解,那么什么是哈希?

kkbca的博客 1509

散列表(哈希表)各种方法实现

本文为散列表(哈希表)的源代码,如若想看算法具体介绍请点击下面链接: http://blog.youkuaiyun.com/aytfly/article/details/8986920   /** * @brief Hash Table * @author An * @data 2013.5.28

aytfly的专栏 875

Java实现哈希表(散列表)

Java实现哈希表(散列表)

qq_64431576的博客 2579

哈希表(散列表)介绍及实现

提供一个仿函数来把string或者其他自定义类型通过某种映射的方式把他们转换为整形 然后再用这里的映射关系二次映射这里用string来举例我们可以用仿函数的方式来解决但是这种string映射为int的方式是不好的 很容易就发生重复 例如 abc acb bbb他们映射为整形的结果是一模一样的我们可以用下面这种映射关系把string映射为int 这里的131 就是一个质数 是有人专门研究过的 可以最大程度上减小冲突这样哈希表就支持string类型的使用了。

moringlightyn的博客 1132

C++中的unordered_set,unordered_map,哈希表/散列表以及哈希表的模拟实现

本节首先介绍了unordered_set和unordered_map,然后借此引出了哈希/散列和哈希表/散列表的概念;然后着重分析了哈希表这一数据结构,提到了哈希函数和哈希冲突处理方法这两个概念,再分别介绍了常用的哈希函数:直接定址法和除留余数法,常用的哈希冲突处理:闭散列开放定址法(线性探测,二次探测)和开散列哈希桶法,同时就如何支持多种类型的key来使用的问题,以string为例进行了详细分析

tianxhiliangtadi的博客 1293

散列表(哈希表)的实现

散列函数直接用key%size的形式,size为散列表的大小。 冲突处理采用平方探测法,为保证可以探测到整个散列表空间,散列表大小设置为4k+3形式的素数。 当散列表中的元素过多时会造成性能下降,这时应该倍增散列表的大小,重新计算原来散列表中每个元素在新的散列表中的位置。 散列表的实现 // HashTable.cpp : 定义控制台应用程序的入口点。 // #inc

Marshall的专栏 1607
上一篇: A星寻路算法
下一篇: 平衡二叉树(AVL)
靠普科技
博客等级 码龄7年 14粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值