C++进阶 —— 哈希

一篇文章搞懂C++实现哈希算法 哈希算法,也称为散列算法,是一种从任意长度的输入数据创建固定大小输出的方法,这种输出通常被称为“哈希值”、“散列值”或简单地“哈希”。在计算机科学中,哈希算法主要用于快速数据查找和数据结构中的高效数据管理,如哈希表。哈希也是加密和数据完整性验证的基础。哈希算法通过一个称为哈希函数的数学过程来运作。这个函数接受输入(称为“预映射值”)并返回一个通常较短、固定长度的哈希值。这个哈希值在理想情况下为每个不同的输入值提供一个唯一的标识(尽管在实际中这并不总是可能的)。 阅读详情

目录

一,哈希的介绍

二,哈希函数

二,哈希冲突解决

闭散列

开散列

开散列与闭散列比较


        在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,查询效率可达到logN,即最差情况下需要比较红黑树的高度次,当树节点非常多时,查询效率也不理想;最好的查询是,进行很少的比较次数就能够将元素找到,因此C++11,STL又提供了4个unordered系列的关联式容器(unordered_set/unordered_map、unordered_multiset/unordered_multimap),这4个容器与红黑树结构的关联式容器使用方式基本类似,只是结构不同;

一,哈希的介绍

        unordered系列关联式容器之所以效率高,是因为其底层使用了哈希结构;

        顺序结构以及平衡树中,元素与其存储位置没有对应关系,因此在查找元素时,必须经过元素的多次比较;顺序查找时间复杂度为O(N),平衡树中为树的高度即O(logN),搜索效率取决于搜索过程中的比较次数;

        理想的搜索方法,即可不经过任何比较,一次直接从表中得到要搜索的元素;如构造一种存储结构,通过某种函数(hashFunc)使元素的存储位置与它的元素之间能够建立一一对应的关系,那么在查找时通过该函数可以很快找到该元素;

插入元素,根据待插入元素关键码,以此函数计算出该元素的存储位置并按次位置进行存放;

搜索元素,对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键码相等,则搜索成功;

        该方式称为哈希(散列)方法,哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表(散列表)Hash Table;

该方法进行搜索不必进行多次元素比较,因此搜索速度较快;

二,哈希函数

哈希冲突

  • 对于两个元素的关键码k_{i}、k_{j},当hash(k_{i})==hash(k_{j}),即不同关键码通过相同哈希函数计算出相同的哈希地址,称为哈希冲突或哈希碰撞;
  • 把具有不同关键码而具有相同哈希地址的数据元素称为“同义词”;

引发哈希冲突的原因可能是,哈希函数设计不够合理;

哈希函数设计原则

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

常见哈希函数

  • 直接定制法(常用)
    • 取关键码的某个线性函数作为散列地址,Hash(Key)=A*Key+B;
    • 适合查找比较小且连续的情况;
    • 优点,简单、均匀;
    • 缺点,需要事先知道关键码的分布情况;
  • 除留余数法(常用)
    • 假设散列表中允许的地址数为m,取一个不大于m,但最接近或等于m的质子p作为除数,按照哈希函数Hash(Key)=Key%p(p<m),将关键码转换成哈希地址;
  • 平方取中法(了解)
    • 假设关键码为1234,对其平方就是1522756,抽取中间3位227作为哈希地址;
    • 在如关键码为4321,对其平方就是18671041,抽取中间3为671(或710)作为哈希地址;
    • 比较适合不知道关键码的分布,而位数又不是很大的情况;
  • 折叠法(了解)
    • 是将关键码从左到右分割成位数相等的几部分(最后一部分位数可以短些),然后将这几部分叠加求和,并按散列表长,取后几位作为散列表地址;
    • 适合事先不知道关键码的分布,适合关键码位数比较多的情况;
  • 随机数法(了解)
    • 选择一个随机函数,取关键码的随机函数值为它的哈希地址,Hash(Key)=random(Key);
    • 通常应用于关键码长度不等时常用此法;
  • 数学分析法(了解)
    • 设有n个d位数,每一位可能有r种不同的符号,这r种不同的符号在各位上出现的频率不一定相同,可能 在某些位上分布比较均匀,每种符号出现的机会均等,在某些位上分布不均匀只有某几种符号经常出现。可根据散列表的大小,选择其中各种符号分布均匀的若干位作为散列地址;
    • 适合处理关键码位数比较大的情况,如事先折叠关键码的分布且关键码的若干位分布较均匀的情况;

注:哈希函数设计的越精妙,哈希冲突就越低,但无法避免哈希冲突;

二,哈希冲突解决

        解决哈希冲突常见方法,闭散列、开散列;

闭散列

        也叫开放定址法,当发生哈希冲突时,如哈希表未被装满,说明在哈希表中必然还有空位置,那么可把key存放到冲突位置中的“下一个”空位置中去,寻找“下一个”空位置方法有,线性探测和二次探测;

1,线性探测

        如上述案例中,在插入元素44,计算的哈希地址为4,但该位置已存放了元素,发生了哈希冲突;线性探测,从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止;

  • 插入,通过哈希函数获取插入哈希表中的位置;
    • 如该位置没有元素直接插入;
    • 如该位置已有元素使用线性探测找到下一个空位置,插入新元素;
  • 删除,采用闭散列处理哈希冲突时,不能随便物理删除哈希表中已有元素,若直接删除会影响其他元素的搜索;因此线性探测采用标记的伪删除法来删除元素;
//哈希表每个空间给个标记
//EMPTY为空,EXISTY已有元素,DELETE元素已删除
enum State {
    EMPTY,   // 空槽
    EXIST,   // 有元素
    DELETE   // 元素被删除(墓碑状态)
};

优点:实现非常简单;

缺点:一旦发生哈希冲突,所有的冲突连在一起,容易发生数据堆积,即不同关键码占据了可利用的空位置,使得寻找某关键码的位置需要许多次比较,导致效率低下;

//线性探测的实现
template<class K, class V>
class HashTable
{
private:
	struct Elem
	{
        Elem() : _state(EMPTY) {}
		pair<K, V> _val;
		State _state;
	};

	vector<Elem> _ht;
	size_t _size;

	size_t HashFunc(const K& key)
		return key % _ht.capacity();

public:
	HashTable(size_t capacity = 3)
		:_ht(capacity, _size(0))
	{
		for (size_t i = 0; i < capacity; ++i)
		{
			_ht[i]._state = EMPTY;
		}
	}

	bool Insert(const pair<K, V>& val)
	{
		size_t hashAddr = HashFunc(key);
		while (_ht[hashAddr] != EMPTY)
		{
			if (_ht[hashAddr]._state == EXIST && _ht[hashAddr]._val.first == key)
				return false;
			hashAddr++;
			if (hashAddr == _ht.capacty())
				hashAddr = 0;
		}
		_ht[hashAddr]._state = EXIST;
		_ht[hashAddr]._val = val;
		_size++;
		return true;
	}

	int Find(const K& key)
	{
		size_t hashAddr = HashFunc(key);
        size_t startAddr = hashAddr;

		while (_ht[hashAddr]._state != EMPTY)
		{
			if (_ht[hashAddr]._state == EXIST && _ht[hashAddr]._val._first == key)
				return hashAddr;
			hashAddr++;
			if (hashAddr == _ht.capacty())
				hashAddr = 0;
		}
        if (hashAddr == startAddr) break;
		return -1;
	}

	bool Erase(const K& key)
	{
		int index = Find(key);
		if (index != -1)
		{
			_ht[index]._state = DELETE;
			_size--;
			return true;
		}
		return false;
	}
};

哈希表扩容

        散列表的载荷因子定义为:\alpha = 填入表中的元素个数 / 散列表的长度

        \alpha是散列表装满程度的标志因子,由于表长是定值,\alpha与“填入表中的元素个数”成正比,\alpha越大填入表中元素越多,产生冲突的可能性越大;反之,\alpha越小填入表中的元素越少,产生冲突的可能性就越小;实际上,散列表的平均查找长度是载荷因子\alpha的函数,只是不同处理冲突的方法有不同的函数;

        对于开放定址法,载荷因子是特别重要因素,应严格限制在0.7-0.8以下;超过0.8,查表时cpu缓存不命中(cache missing)按照指数曲线上升,因此一些采用开放定址法的hash库,如Java的系统库限制了载荷因子为0.75,超过此值将resize散列表;

void CheckCapacity()
{
	if (_size * 10 / _ht.capacity() >= 7)
	{
		HashTable(K, V, HF) newHt(GetNextPrime(ht.capacity));
		for (size_t i = 0; i < _ht.capacity(); ++i)
		{
			if (_ht[i]._state == EXIST)
				newHt.Insert(_ht[i]._val);
		}
		Swap(newHt);
	}
}

2,二次探测

        线性探测的缺陷时产生冲突的数据堆积在一块,这与其找下一个位置有关系,因为找空位置的方式就是挨个往后逐个查找的;二次探测就是为了避免该问题的,找下一个空位置的方法为,H_{i}=(H_{0}+i^{2})%m 或 H_{i}=(H_{0}-i^{2})%m(i=1,2,3...,H_{0}是通过散列函数Hash(X)对元素的关键码key进行计算得到的位置,m表示表的大小);

        研究表明,当表长度为质数且表转载因子\alpha不超过0.5时,新表项一定能够插入,而且任何一个位置都不会被探查两次,因此只要表中有一半的位置,就不会存在表满的问题,在搜索时可以不考虑表装满的情况,但在插入时必须确保表的装载因子\alpha不超过0.5,如超过需考虑增容;

         因此,闭散列最大的缺陷就是空间利润率较低,这也是哈希的缺陷;

开散列

        又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头节点存储在哈希表中;

在开散列中,每个桶中放的都是发生哈希冲突的元素;

//开散列的实现
template<class V>
struct HashBucketNode
{
	HashBucketNode(const V& data)
		:_pNext(nullptr)
		,_data(data)
	{}

	HashBucketNode<V>* _pNext;
	V _data;
};

template<class V>
class HashBucket
{
	typedef HashBucketNode<V> Node;
	typedef Node* pNode;
private:
	vector<pNode*> _ht;
	size_t _size;

	size_t HashFunc(const V& data)
		return data % _ht.capacity();

public:
	HashBucket(size_t capacity = 3)
		:_size(0)
	{
		_ht.resize(GetNextPrime(capacity), nullptr);
	}

	pNode* Insert(const V& data)
	{
		size_t bucketNo = HashFunc(data);
		pNode pCur = _ht[bucketNo];
		while (pCur) //查找插入元素是否已存在
		{
			if (pCur->_data == data)
				return pCur;
			pCur = pCur->_pNext;
		}
		pCur = new Node(data);
		pCur->_pNext = _ht[bucketNo];
		_ht[bucketNo] = pCur;
		_size++;
		return pCur;
	}

	pNode* Erase(const V& data)
	{
		size_t bucketNo = HashFunc(data);
		pNode pCur = _ht[bucketNo];
		pNode pPrev = nullptr;
		pNode pRet = nullptr;
		while (pCur)
		{
			if (pCur->_data == data)
			{
				if (pCur == _ht[bucketNo])
					_ht[bucketNo] = pCur->_pNext;
				else
					pPrev->_pNext = pCur->_pNext;
				pRet = pCur->_pNext;
				delete pCur;
				_size--;
				return pRet;
			}
            pPrev = pCur;
            pCur = pCur->_pNext;
		}
		return nullptr;
	}

	pNode* Find(const V& data);
	size_t Size()const;
	bool Empty()const;
	void Clear();
	bool BucketCount()const;
	void Swap(HashBucket<V, HF>& ht);
	~HashBucket();
};

开散列增容

        桶的个数是一定的,随着元素的不断插入,每个桶中的元素个数会不断增加,可能会导致一个桶中链表节点非常多,进而影响哈希表的性能,因此在一定条件下需要对哈希表进行增容;开散列最好的情况是:每个哈希桶中刚好挂一个节点,再继续插入元素时,每一次都会发生哈希冲突,因此在元素个数刚好等于桶个数时,可给哈希表增容;

void _CheckCapacity()
{
	size_t bucketCount = BucketCount();
	if (_size == bucketCount)
	{
		HashBucket<V, HF> newHt(bucketCount*2);
		for (size_t bucketIdx = 0; bucketIdx < bucketCount; ++bucketIdx)
		{
			pNode pCur = _ht[bucketIdx]; //遍历每个旧桶
			while (pCur)
			{
				_ht[bucketIdx] = pCur->_pNext; //记录旧桶中的下一个节点
				size_t bucketNo = newHt.HashFunc(pCur->_data); 
				pCur->_pNext = newHt._ht[bucketNo]; //将该节点的下一个节点连接到新桶的头节点;
				newHt._ht[bucketNo] = pCur; //新桶连接到该节点;
				pCur = _ht[bucketIdx]; //旧桶的下一个节点
			}
		}
		newHt._size = _size;
		this->Swap(newHt);
	}
}

开散列的思考

只能存储key为整数的元素,其他类型怎么解决?

除留余数法,最好模一个素数,如何每次快速取一个类似两倍关系的素数?

开散列与闭散列比较

        应用链地址法处理溢出,需增设链接指针,似乎增加了存储开销;事实上,由于开地址法必须保持大量的空闲空间以确保搜索效率,如二次探查法要求转载因子\alpha<=0.7,而表项所占空间又比指针大的多,所以使用链地址法反而比开地址法节省存储空间;

、

【C++】-- 哈希算法 如果构造一种存储结构,通过某种函数(hashFunc)使元素的存储位置与它的key之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素。 向该结构中插入元素和查找元素时: 插入元素:将元素key存放到用hashFunc计算出的元素key的位置。 查找元素:对元素的key进行计算,把用hashFunc计算的函数值当做元素的存储位置,在哈希结构中按此位置取元素比较,若key相等,则查找成功。 阅读详情

相关推荐

C++哈希算法详解(hash、hash!)

C++哈希算法详解

2401_90042730的博客 1974

[C++] 哈希详解

哈希

weixin_43717520的博客 9286

C++进阶——哈希的实现

在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到O(log2​N),即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。

weixin_43635473的博客 1276

【C++】哈希

哈希表的基本概念以及如何分别使用闭散列和开散列来模拟实现哈希表。

在平淡的日子里寻找存在的价值 3790

C++11 std::hash 实战进阶:从内置类型到自定义哈希

本文深入探讨了C++11中std::hash的实战应用,从内置类型到自定义哈希的实现方法。通过详细示例和技巧分享,帮助开发者掌握如何为自定义类型实现高效的哈希函数,优化unordered容器的性能,并避免常见陷阱。

weixin_30781107的博客 300

资源描述框架RDF及Turtle

文章目录1. RDF1.1 简介1.2 格式1.3 RDF的要求2. Turtle2.1 语法2.1.1 简单三元组2.1.2 Turtle中的命名空间2.1.3 Base URI2.1.4 谓语列表2.1.5 宾语列表2.1.6 空白节点(bNodes)2.1.7 数据类型2.1.8 Class membership2.1.9 空URI2.1.10 集合 1. RDF 1.1 简介 RDF(Resource Description Framework)语义网的标准数据模型,是一个用于描述 Web 上的资

doublewhite233的博客 2493

c++进阶——哈希表

简单说:三个名字表示三种情况,但是这三个名字底层都是整数值。

2401_83052144的博客 1275

软件工程期末知识点总结【超详细】

生命周期模型(过程模型):瀑布模型、快速原型模型、增量模型、螺旋模型、喷泉模型。2、实体联系图:1、数据对象2、属性3、联系(1:1、1:N、M:N)3、语句覆盖 就是设计足够的调试用例,使得程序中的每个语句至少执行一次。 5、判定覆盖就是设计足够的测试用例,使得程序中每个判定的取“真”分支和取“假”分支至少都执行一次,判定覆盖又称分支覆盖 6、条件覆盖就是设计足够的测试用例,使得程序判定中的每个条件能获得各种可能的结果。7、软件开发时期通常分成4个阶段:总体设计、详细设计、编码和单元测试、综合测试。

这个人好有趣....hh 1万+

《C++进阶之STL》【哈希表】

本文介绍了哈希表的核心概念和关键术语,重点解析了哈希函数的设计原理和常见类型。文章详细讲解了直接定址法和除法散列法两种哈希函数,分析其优缺点及适用场景。最后指出哈希函数的选择需结合实际场景,平衡性能与资源消耗。全文为理解哈希表实现机制提供了理论基础。

序属秋秋秋的博客 4965

Jetson Orin Nano GPIO 实战,用 devmem 玩转 Pinmux 引脚复用配置

devmem 是一个直接读写寄存器的工具,通过 mmap 将 /dev/mem 中的物理地址区域映射到用户空间进程地址空间,从而实现直接读写,正常情况下在 /dev 下可以看到 mem。可以看到对应 bit5 bit6 分别为 1,对应配置为 E_IO_HV 为 ENABLE 以及 E_INPUT 为 ENABLE。需要 TRM 手册查看相关寄存器,以及安装 busybox,busybox 内置了 devmem。根据 TRM 手册,找到 I2C_SDA 的 pinmux 地址偏移是 0x18。

darcsdn 1643

Linux 音频驱动(六) ALSA音频驱动之PCM Write数据传递过程

目录1. 前言2. PCM Data Flow3. 总结 1. 前言 本文,我们将以回放(Playback,播放音频)为例,讲解PCM Data是如何从用户空间到内核空间,最后传递到Codec。 在Linux 音频驱动(一) ASoC音频框架简介中,我们给出了回放(Playback)PCM数据流示意图: 对于Linux来说,由于分为 user space 和kernel space,而且两者之间不能随便互相访问。因此用户如果播放音频,则需要调用copy_from_user()将用户数据从user spa

_Modest_的博客 1万+

C++进阶:哈希

哈希(hash)⼜称散列,是⼀种组织数据的⽅式。从译名来看,有散乱排列的意思。本质就是通过哈希函数把关键字Key跟存储位置建⽴⼀个映射关系,查找时通过这个哈希函数计算出Key存储的位置,进⾏快速查找。

QinMou 1120

国产Flash替代方案:手把手教你用XSCT烧写ZYNQ7045的BOOT.BIN(附完整命令解析)

本文详细介绍了国产Flash替代方案在ZYNQ7045上的应用,通过XSCT工具链实现BOOT.BIN的精准烧写。内容涵盖国产Flash兼容性检查、PetaLinux环境搭建、XSCT烧写全流程及故障排查,帮助开发者高效完成国产化替代,提升硬件开发效率。

weixin_33670786的博客 424

C++进阶—哈希

在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到log₂N,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。

Awkwardx的博客 856

【unity】解决unity编译器安装中文汉化包失败

查看是否有Localization目录如果没有就进行创建,然后点击打开Localization把下载的zh-hans.po文件复制剪切进去即可。如果有的同学中文包安装失败,我们找到相应的编译器版本,点击在资源管理器中显示按钮,我们找到简体中文,复制downloadUrl后面的值到浏览器打开进行下载,点击Edtior language选择框,选择简体中文,等待加载。我们点击当前目录的上一级,进入编译器目录。返回在文件管理器中点击Editor目录。编译器启动后点击Edit[编辑]按钮。复制或者剪切下载的文件。

weixin_44959182的博客 8022

245. 项目195:简易文字冒险游戏——《跟老吕学Python·新手》

如果您在学习本专栏教程时遇到任何问题,或有任何技术交流的意愿,欢迎在文章评论区留言,或通过优快云私信与老吕取得联系。老吕将及时回复您的留言,并与您共同探讨,以期为大家提供更为精准和有效的帮助。老吕珍视每一位读者的反馈和支持,期待与您共同学习、共同进步,共同创造美好的未来!我们的目标是不仅教会您Python语言,更是培养您解决问题的思维方式。请随意翻阅,按照自己的节奏学习,让这本专栏成为您编程旅程中的可靠伙伴。开发一个简易的文字冒险游戏,通过文本描述场景和事件,让玩家通过选择不同的选项来推动故事发展。

Python老吕的博客 711

【C++进阶】哈希

桶的个数是一定的,随着元素的不断插入,每个桶中元素的个数不断增多,极端情况下,可能会导致一个桶中链表节点非常多,会影响的哈希表的性能,因此在一定条件下需要对哈希表进行增容,那该条件怎么确认呢?开散列最好的情况是:每个哈希桶中刚好挂一个节点,再继续插入元素时,每一次都会发生哈希冲突,因此,在元素个数刚好等于桶的个数时,可以给哈希表增容。问题来了,新闻客户端推荐系统如何实现推送去重的?对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键码相等,则搜索成功。

Caihua的博客 1176

MCAL中Dsadc的配置

DSADC模块作为一个专用的模块,主要应用在编码器软解码,功能强大而复杂,这里介绍了Dsadc的mcal配置和详细描述,让你全面学习和理解这个模块功能和应用。

dhyw12399999的博客 787

C/C++语言进阶-哈希表 <哈希表完全解析:从算法原理到C语言实战,一次彻底搞懂Hash!>

哈希表完全解析:从算法原理到C语言实战,一次彻底搞懂Hash! 内容较多,但非常全面,内容涵盖了哈希表从算法原理 → 代码实现 → 实际应用 → 面试考点的全流程,非常适合做学习资料或面试复盘。 本文将带你从零开始,深入理解哈希算法的原理与实现,掌握链地址法、开放寻址法、负载控制与扩容机制,并通过完整C语言示例代码构建自己的哈希库。 无论你是准备面试、写底层代码,还是做嵌入式内存优化,这都是一篇你读完就能上手实战的 Hash 全指南。

csyys1的博客 657

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

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

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

c++进阶——哈希

1. unordered系列关联式容器2. 底层结构3. 模拟实现4.哈希的应用5.海量数据处理面试题。

2201_75453663的博客 1178

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

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

C++进阶——哈希

哈希结构是一种可以不经过任何比较,一次直接从表中得到要搜索的元素的数据结构。如果构造一种存储结构,通过某种函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射关系,那么在查找时通过该函数可以很快找到该元素。通过哈希构造的方式称为为哈希(散列)方法,哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表(Hash Table)或散列表。

Bit_qnw的博客 1021

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

C++进阶 | [5] 哈希

摘要:概念——哈希、哈希表、哈希碰撞、负载因子;实现哈希表(插入删除查找)(开放定址法)

fantastic_13_7的博客 878

【C++进阶】hash表的封装

通过对哈希表的封装,我们不仅提升了代码的可读性和复用性,还通过合理设计哈希函数和处理冲突机制,优化了哈希表的性能。封装让我们可以将底层的细节隐藏起来,提供一个简洁高效的接口,便于后续在项目中的使用。在实际开发中,理解负载因子、再散列等概念,并针对具体场景合理调整这些参数,能够确保哈希表在性能和内存占用上的平衡。掌握了这些知识后,相信你能够更加自信地在复杂应用中使用哈希表。

2301_79969994的博客 1929

c++进阶——哈希表的实现

本文介绍了哈希表的基本概念及其实现方式。哈希表通过哈希函数将关键字映射到存储位置,以实现快速查找和插入。C++ STL库中的unordered_set和unordered_map基于哈希表实现,与基于红黑树的set和map相比,哈希表在搜索和插入效率上更高,但无序。哈希表的关键在于将关键字转化为整型并通过哈希函数映射到表中,这可能导致哈希冲突。解决冲突的常用方法有开放定址法和链地址法。开放定址法通过线性探测等方式解决冲突,而链地址法则通过链表或红黑树处理冲突。哈希函数的选取对哈希表的性能至关重要,常见的哈希

2301_79705195的博客 1118

C++进阶--哈希

哈希(Hash)是一种常见的密码学技术和数据结构,。。唯一性固定长度高效性不可逆性。

m0_74068921的博客 2859
上一篇: C++进阶 —— 红黑树
下一篇: C++进阶 —— auto/decltype(C++11新特性)
挨代码
博客等级 码龄5年 1696粉丝 384原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值