C++实现哈希桶

#pragma once

#include <vector>
#include <string>

template<class K, class V>
struct HashTableNode
{
	K _key;
	V _value;
	HashTableNode<K, V>* _next;

	HashTableNode(const K& key, const V& value)
		:_key(key)
		,_value(value)
		,_next(NULL)
	{}
};

template<class K>
struct __HashFunc
{
	size_t operator()(const K& key)
	{
		return key;
	}
};

template<>
struct __HashFunc<string>
{
	static size_t BKDRHash(const char * str)
	{
		unsigned int seed = 131; // 31 131 1313 13131 131313
		unsigned int hash = 0;
		while (*str)
		{
			hash = hash * seed + (*str++);
		}
		return (hash & 0x7FFFFFFF);
	}

	size_t operator() (const string& key)
	{
		return BKDRHash(key.c_str());
	}
};

template<class K, class V, class HashFunc = __HashFunc<K>>
class HashTable
{
	typedef HashTableNode<K, V> Node;
public:
	HashTable(size_t capacity)
		:_size(0)
	{
		_tables.resize(_GetNextPrime(capacity));
	}

	HashTable(const HashTable<K, V>& ht);
	HashTable<K, V>& operator=(const HashTable<K, V>& ht);

	~HashTable()
	{
		for (size_t i = 0; i < _tables.size(); ++i)
		{
			Node* cur = _tables[i];

			while (cur)
			{
				Node* del = cur;
				cur = cur->_next;
				delete del;
			}
		}
	}

	bool Insert(const K& key, const V& value)
	{
		_CheckCapacity();

		size_t index = _HashFunc(key, _tables.size());

		Node* cur = _tables[index];

		while (cur)
		{
			if (cur->_key == key)
				return false;

			cur = cur->_next;
		}

		Node* tmp = new Node(key, value);
		tmp->_next = _tables[index];
		_tables[index] = tmp;

		++_size;

		return true;
	}

	Node* Find(const K& key)
	{
		size_t index = _HashFunc(key, _tables.size());
		Node* cur = _tables[index];
		while (cur)
		{
			if (cur->_key == key)
				return cur;

			cur = cur->_next;
		}

		return NULL;
	}

	bool Remove(const K& key)
	{
		size_t index = _HashFunc(key, _tables.size());

		if (_tables[index] == NULL)
			return false;

		if (_tables[index]->_key == key)
		{
			Node* del = _tables[index];
			_tables[index] = _tables[index]->_next;
			delete del;

			return true;
		}

		Node* prev = _tables[index];
		Node* cur = prev->_next;
		while (cur)
		{
			if (cur->_key == key)
			{
				prev->_next = cur->_next;
				delete cur;

				return true;
			}

			prev = cur;
			cur = cur->_next;
		}

		return false;
	}

	void Print()
	{
		for (size_t i = 0; i < _tables.size(); ++i)
		{
			printf("[%d]->", i);
			Node* cur = _tables[i];
			while (cur)
			{
				cout<<cur->_key<<":"<<cur->_value<<"->";

				cur = cur->_next;
			}

			cout<<"NULL"<<endl;
		}

		cout<<endl;
	}

	void Swap(HashTable<K, V>& ht)
	{
		swap(_tables, ht._tables);
		swap(_size, ht._size);
	}

protected:
	void _CheckCapacity()
	{
		if (_size == _tables.size())
		{
			size_t newCapacity = _GetNextPrime(_tables.size());

			if (newCapacity == _tables.size())
				return;
/*

			vector<Node*> newTables;
			newTables.resize(newCapacity);

			for (size_t i = 0; i < _tables.size(); ++i)
			{
				Node* cur = _tables[i];

				while (cur)
				{
					Node* tmp = cur;
					cur = cur->_next;

					size_t index = _HashFunc(tmp->_key, newCapacity);//???
					tmp->_next = newTables[index];
					newTables[index] = tmp;
				}

				_tables[i] = NULL;
			}

			_tables.swap(newTables);
*/

			HashTable<K, V> tmp(_tables.size());
			for (size_t i = 0; i < _tables.size(); ++i)
			{
				Node* cur = _tables[i];

				while (cur)
				{
					tmp.Insert(cur->_key, cur->_value);
					cur = cur->_next;
				}
			}

			this->Swap(tmp);
		}
	}

	// 使用素数表对齐做哈希表的容量,降低哈希冲突
	size_t _GetNextPrime(size_t size)
	{
		const int _PrimeSize = 28;
		static const unsigned long _PrimeList [_PrimeSize] =
		{
			53ul,         97ul,         193ul,       389ul,       769ul,
			1543ul,       3079ul,       6151ul,      12289ul,     24593ul,
			49157ul,      98317ul,      196613ul,    393241ul,    786433ul,
			1572869ul,    3145739ul,    6291469ul,   12582917ul,  25165843ul,
			50331653ul,   100663319ul,  201326611ul, 402653189ul, 805306457ul,
			1610612741ul, 3221225473ul, 4294967291ul
		};

		for (size_t i = 0; i < _PrimeSize; ++i)
		{
			if (_PrimeList[i] > size)
			{
				return _PrimeList[i];
			}
		}

		return _PrimeList[_PrimeSize-1];
	}

	size_t _HashFunc(const K& key, const size_t capacity)
	{
		return HashFunc()(key) % capacity;
	}
protected:
	vector<Node*> _tables;
	size_t _size;
};

void TestDic()
{
	HashTable<string, string> dict(10);

	dict.Insert("he", "他");
	dict.Insert("she", "她");
	dict.Insert("hash", "哈希");
	dict.Insert("hello", "你好");
	dict.Print();

	HashTableNode<string, string>* ret = dict.Find("hash");
	if (ret)
	{
		cout<<ret->_value<<endl;
	}
}

void Test()
{
	HashTable<string, vector<string>> ht(10);
	vector<string> vec;

	vec.push_back("男");
	vec.push_back("20");
	vec.push_back("123456");

	ht.Insert("张三", vec);

	HashTableNode<string, vector<string>>* ret = ht.Find("张三");
	if (ret)
	{
		cout<<"姓名:"<<ret->_key<<endl;
		cout<<"性别:"<<ret->_value[0]<<endl;
		cout<<"年龄:"<<ret->_value[1]<<endl;
		cout<<"电话号码:"<<ret->_value[2]<<endl;
	}
}
#include <iostream>
using namespace std;
#include "HashTablesBucket.h"

int main()
{
	//TestDic();
	Test();

	return 0;
}

TestDic:

Test:

时间: 2024-08-10 23:20:51

C++实现哈希桶的相关文章

openVswitch(OVS)源码分析之工作流程(哈希桶结构体的解释)

这篇blog是专门解决前篇openVswitch(OVS)源码分析之工作流程(哈希桶结构体的疑惑)中提到的哈希桶结构flex_array结构体成员变量含义的问题. 引用下前篇blog中分析讨论得到的flex_array结构体成员变量的含义结论: struct { int element_size; // 这是flex_array_part结构体存放的哈希头指针的大小 int total_nr_elements; // 这是全部flex_array_part结构体中的哈希头指针的总个数 int e

【数据结构】处理哈希冲突的开链法(哈希桶)算法实现

实现哈希表时,我们常见的方法是线性探测.二次探测,这两个算法也很简单.若有兴趣,可以查看我的博客.但是,这两个算法有一个共同点就是:空间利用率低.为什么这么说呢?线性探测.二次探测的高效性很大程度上要取决于它的载荷因子,载荷因子即:存放关键字个数/空间大小. 通过查阅资料,我发现,使用素数做除数可以减少哈希冲突(具体原因不详,大师专研的,发现很好用,就在这里分享给大家).见下: ----素数表 // 使用素数表对齐做哈希表的容量,降低哈希冲突 const int _PrimeSize = 28;

哈希桶

哈希桶:哈希桶就是盛放不同key链表的容器(即是哈希表),在这里我们可以把每个        key的位置看作是一个孔,孔里放了一个链表.或是使用一个顺序表来存放具        有相同哈希值的key的链表的头节点,利用这个头节点可以找到其它key值.

【干货】C++哈希桶(开链法解决哈希冲突)类的实现

开链法(哈希桶)是解决哈希冲突的常用手法,结构如下: 数据结构的设计思路是这样的,定义一个K-V的链式节点(Node),以数组方式存储节点指针 实现代码如下: #include<vector> #include"HashTable.h" size_t GetSize() { static size_t index = 0; const int _PrimeSize = 28; static const unsigned long _PrimeList[_PrimeSize]

哈希算法(一次探测,二次探测,哈希桶法)支持字典查询

HashTable-散列表/哈希表,是根据关键字(key)而直接访问在内存存储位置的数据结构.它通过一个关键值的函数将所需的数据映射到表中的位置来访问数据,这个映射函数叫做散列函数,存放记录的数组叫做散列表. 构造哈希表的几种方法 直接定址法--取关键字的某个线性函数为散列地址,Hash(Key)= Key 或 Hash(Key)= A*Key + B,A.B为常数. 除留余数法--取关键值被某个不大于散列表长m的数p除后的所得的余数为散列地址.Hash(Key)= Key % P. 平方取中法

C++ 哈希表 线性探测 二次探测 哈希桶

#pragma once #include<iostream>//含一次探测  二次探测 #include<vector> #include<math.h> using namespace std; enum Status { EXIST, EMPTY, DELET, }; template <class K,class V> //key/value形式结构体 struct KV { K _key; V _value; KV(const K& key

哈希桶的实现

#pragma once#include<vector> template<class K>struct __HashFunc{    size_t operator()(const K&key)    {        return key;    }}; template<>struct __HashFunc<string>   //特化{    static size_t BKDRHash(const char*str)    //BKDRHa

哈希桶处理哈希冲突

哈希桶:哈希桶就是盛放不同key链表的容器(即是哈希表),我们可以把每个key的位置看作是一个指针,该指针所指向的位置里放了一个链表,可以认为是指针数组,故该方法也叫开链式. 相比闭散列,哈希桶提高了空间利用率:在实现哈希表时,常见的方法是线性探测.二次探测,这两个算法的具体实现可以查看我的博客.但是这两个算法有一个共同点就是:空间利用率低.为什么这么说呢?线性探测.二次探测的高效性很大程度上要取决于它的载荷因子,载荷因子即:存放关键字个数 / 空间大小. 通过查阅资料,我发现,使用素数做除数可

Linux内核哈希表中的bucket桶

哈希表 哈希表(Hashtable)又称为“散列”,Hashtable是会根据索引键的哈希程序代码组织成的索引键(Key)和值(Value)配对的集合.Hashtable 对象是由包含集合中元素的哈希桶(Bucket)所组成的.而Bucket是Hashtable内元素的虚拟子群组,可以让大部分集合中的搜寻和获取工作更容易.更快速. 哈希函数(Hash Function)为根据索引键来返回数值哈希程序代码的算法.索引键(Key)是被存储对象的某些属性值(Value).当对象加入至 Hashtabl