当前位置: 首页 > article >正文

【C++ 哈希】

文章目录

  • 哈希
    • 闭散列---线性探测
    • 开散列---哈希桶

哈希

C++STL中提供的底层为红黑树结构的map/set,查找时间复杂度为 O ( l o g 2 N ) O(log_2N) O(log2N),最差情况下要比较树高度次,当树中节点很多时,查找效率也不理想。所以C++11新增了底层为哈希结构的关联式容器。
哈希本质是一种映射,通过这种映射关系,可以把一个值放在属于它的位置,同时查找时只需到这个位置上查找即可,这样查找时间复杂度平均为O(1),哈希方法中使用的转换函数称为哈希函数,构造出来的结构称为哈希表。
但如果有两个值映射到同一个位置上,就会产生冲突。不同关键字通过相同哈希映射出相同的地址,该种现象称为哈希冲突或哈希碰撞。

闭散列—线性探测

线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。
插入:通过哈希函数转换出地址,从这个位置开始往后遍历,直到找到一个空位置插入数据
查找:通过哈希函数转换出地址,从这个位置往后遍历直到为空
删除:通过哈希函数转换出地址,从这个位置往后遍历直到为空,如果找到就将这个位置的状态设置为”删除“

	enum Stat
	{
		EMPTY,
		EXIST,
		DELETE
	};

	template<class K, class V>
	struct HashData
	{
		pair<K, V> _kv;
		Stat _state = EMPTY;
	};

	template<class K, class V, class Hash = HashFunc<K>>
	class HashTable
	{
		typedef HashData<K, V> Data;
	public:
		HashTable(size_t size = 10)
		{
			_tables.resize(size);
			_n = 0;
		}

		Data* Find(const K& key)
		{
			Hash hs;
			size_t hashi = hs(key) % _tables.size();
			while (_tables[hashi]._state != EMPTY)
			{
				if (_tables[hashi]._kv.first == key
					&& _tables[hashi]._state == EXIST)
					return &_tables[hashi];
				hashi++;
				hashi %= _tables.size();
			}
			return nullptr;
		}

		bool Insert(const pair<K, V>& kv)
		{
			if (Find(kv.first))
				return false;
			if (_n * 10 / _tables.size() >= 7)
			{
				HashTable<K, V> newTables(_tables.size() * 2);
				for (int i = 0; i < _tables.size(); i++)
				{
					if (_tables[i]._state == EXIST)
						newTables.Insert(_tables[i]._kv);
				}
				_tables.swap(newTables._tables);
			}
			Hash hs;
			size_t hashi = hs(kv.first) % _tables.size();
			while (_tables[hashi]._state == EXIST)
			{
				hashi++;
				hashi %= _tables.size();
			}
			_tables[hashi]._kv = kv;
			_tables[hashi]._state = EXIST;
			++_n;
			return true;
		}
		bool Erase(const K& key)
		{
			auto ret = Find(key);
			if (ret)
			{
				ret->_state = DELETE;
				--_n;
				return true;
			}
			else
			{
				return false;
			}
		}
	private:
		vector<Data> _tables;
		size_t _n;
	};

开散列—哈希桶

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

	template<class K, class V>
	struct HashNode
	{
		pair<K, V> _kv;
		HashNode<K, V>* _next;
		HashNode(const pair<K, V>& kv)
			:_kv(kv)
			,_next(nullptr)
		{}
	};

	template<class K, class V, class Hash = HashFunc<K>>
	class HashTable
	{
		typedef HashNode<K, V> Node;
	public:
		HashTable(size_t size = 10)
		{
			_tables.resize(10, nullptr);
			_n = 0;
		}
		~HashTable()
		{
			for (size_t i = 0; i < _tables.size(); i++)
			{
				if (_tables[i])
				{
					Node* curr = _tables[i];
					while (curr)
					{
						Node* next = curr->_next;
						delete curr;
						curr = next;
					}
				}
				_tables[i] = nullptr;
			}
		}
		Node* Find(const K& key)
		{
			Hash hs;
			size_t hashi = hs(key) % _tables.size();
			if (_tables[hashi])
			{
				Node* curr = _tables[hashi];
				while (curr)
				{
					if (curr->_kv.first == key)
						return curr;
					curr = curr->_next;
				}
			}
			return nullptr;
		}

		bool Insert(const pair<K, V>& kv)
		{
			if (Find(kv.first))
				return false;
			Hash hs;
			if (_n == _tables.size())
			{
				vector<Node*> newTables(_tables.size() * 2, nullptr);
				for (auto e : _tables)
				{
					if (e)
					{
						Node* curr = e;
						while (curr)
						{
							Node* next = curr->_next;
							size_t hashi = hs(curr->_kv.first) % newTables.size();

							curr->_next = newTables[hashi];
							newTables[hashi] = curr;

							curr = next;
						}
						e = nullptr;
					}
				}
				_tables.swap(newTables);
			}

			size_t hashi = hs(kv.first) % _tables.size();
			Node* newnode = new Node(kv);

			newnode->_next = _tables[hashi];
			_tables[hashi] = newnode;
			++_n;
			return true;
		}

		bool Erase(const K& key)
		{
			Hash hs;
			size_t hashi = hs(key) % _tables.size();
			auto ret = Find(key);
			if (ret)
			{
				Node* curr = _tables[hashi];
				if (curr->_kv.first == key)
				{
					_tables[hashi] = curr->_next;
					delete curr;
				}
				else
				{
					while (curr->_next->_kv.first != key)
						curr = curr->_next;
					Node* del = curr->_next;
					curr->_next = del->_next;
					delete del;
				}
				return  true;
			}
			else
			{
				return false;
			}
		}

	private:
		vector<Node*> _tables;
		size_t _n;
	};

http://www.kler.cn/a/274243.html

相关文章:

  • springboot中使用gdal将表中的空间数据转shapefile文件
  • 链接数据Linked Data的深层解读
  • Linux的VIM基本操作
  • 【数据科学导论】第一二章·大数据与数据表示与存储
  • HTTP、HTTPS和SOCKS5代理協議
  • 【JetPack】WorkManager笔记
  • 2024流星全自动网页生成系统重构版源码
  • 微信支付宝--充ChatGPTPLUS/openAI key
  • 5.1.1、【AI技术新纪元:Spring AI解码】Openai chat
  • 鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:Refresh)
  • 恒驰喜讯 | 亮相华为中国合作伙伴大会2024,荣膺最佳服务一致性奖等3大奖项
  • MySQL表字段数据类型设计建议
  • QT信号与槽实现方式
  • 医药工厂5G智能制造数字孪生可视化平台,推进医药企业数字化转型
  • C语言例3-30:位逻辑运算的应用例子
  • 第十三届蓝桥杯省赛CC++ 研究生组
  • 数据挖掘与机器学习 01.绪论引言及概念
  • UDF提权
  • 智能合约 之 ERC-20介绍
  • 2024地方门户源码运营版带圈子动态+加即时通讯(PC电脑端+WAP移动端+H5微信端+微信小程序+APP客户端)
  • 【前端基础】什么是视口?
  • 第二十六天-统计与机器学习SciPy,Scikit-Leaen
  • Laravel Class ‘Facade\Ignition\IgnitionServiceProvider‘ not found 解决
  • docker-compose Install 容器化Windows 系统
  • Java 文件处理完全指南:创建、读取、写入和删除文件详细解析
  • BSD-3-Clause是一种开源软件许可协议