【数据结构】c++实现HashTable(开链法)

#include <iostream>
#include <vector>
using namespace std;

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 DefaultHashFunc
{
	size_t operator()(const K&key)
	{
		return key;
	}
};

template <class K, class V, class HashFun = DefaultHashFunc<K>>
class HashTableBucket
{
	typedef HashTableNode<K, V> Node;
public:
	HashTableBucket()
		:_size(0)
	{}
	HashTableBucket(size_t size)
		:_size(0)
	{
		_tables.resize(size);
	}

	bool Insert(const K&key, const V&value)
	{
		_CheckExpand();
		size_t index = HashFunc(key, _tables.size());
		Node* begin = _tables[index];
		while (begin)
		{
			if (begin->_key == key)
				return false;
			begin = begin->_next;
		}

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

		++_size;
		return true;
	}
	size_t HashFunc(const K&key, size_t capacity)
	{
		HashFun hf;
		return hf(key) % capacity;
	}
	void PrintTables()
	{
		for (size_t i = 0; i < _tables.size(); ++i)
		{
			printf("Tables[%d]->",i);
			Node* cur = _tables[i];
			while (cur)
			{
				cout << "[" << cur->_key << ":" << cur->_value << "]"<<"->";
				cur = cur->_next;

			}
			cout << "NULL"<<endl;
		}
		cout << endl;
	}
protected:
	size_t _GetNextPrime(size_t size)
	{
		static 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];
	}

	void _CheckExpand()
	{
		// 载荷因子到1时进行增容,保证效率
		if (_size == _tables.size())
		{
			size_t newSize = _GetNextPrime(_size);
			if (_size == newSize)
				return;

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

			for (size_t i = 0; i < _tables.size(); ++i)
			{
				Node* cur = _tables[i];
				while (cur)
				{
					// 取节点
					Node* tmp = cur;
					cur = cur->_next;

					// 头插
					size_t newIndex = HashFunc(tmp->_key, newTables.size());
					tmp->_next = newTables[newIndex];
					newTables[newIndex] = tmp;
				}

				_tables[i] = NULL;
			}

			_tables.swap(newTables);
		}
	}
protected:
	vector<HashTableNode<K, V>*> _tables;
	size_t _size;
};

时间: 2024-10-08 18:55:50

【数据结构】c++实现HashTable(开链法)的相关文章

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

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

【干货】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]

【算法与数据结构】图 -- 数组表示法

图的数组表示法 借助一个二维数组表示图,该二维数组的第i行,第j列的值表示从Node[i]到Node[j]: 无向图(网):是否有边 / 权值,arr[i][j] == arr[j][i],无向图(网)的特性,矩阵关于对角线对称. 有向图(网):是否有弧 / 权值. //图的数组表示法 //最大顶点个数 const int MAX_VERTEX = 100; //最大值 const int MAX_VALUE = (1 << 31) - 1; typedef struct _tagArcCel

散列碰撞问题的解决——开链法(拉链法)

function HashTable() { this.table = new Array(137);//137——官方比较好的设置数组大小的值 this.buildChains = buildChains; this.simpleHash = simpleHash; this.showDistro = showDistro; this.put = put; //this.get=get; } function buildChains() {//核心方法 for ( var i = 0; i <

【算法数据结构Java实现】欧几里得算法

1.背景 欧几里得算法是一个求最大因子的快速算法.如果m,n存在最大因子k,假设m=x*n+r,那么m和n可以整出k的话,r也肯定可以整除k 因为定理:如果M>N,则M mod N<M/2 ,说明时间复杂度是O(log(n)) 2.代码 package Algorithm_analysis; public class Euclid { public static void main(String[] args){ int m=63; int n=18; int remainder=0; whi

java 数据结构与算法 之查找法

一.二分查找法 二分查找就是将查找的键和子数组的中间键作比较,如果被查找的键小于中间键,就在左子数组继续查找:如果大于中间键,就在右子数组中查找,否则中间键就是要找的元素. @Test public void searchDuty(){ Integer[]t=new Integer[]{1,2,3,4,5,6};//原数组 Integer key=10;//目标元素 Integer start=0;//开始位置 Integer end=t.length-1;//结束位置 while(start<

哈希表(开链法)

纯代码 #pragma once #include <iostream> #include <vector> using namespace std; struct __HashFuncString { size_t operator()(const string &key) { size_t hash = 0; for (size_t i = 0; i < key.size(); ++i) { hash += key[i]; } return hash; } };

数据结构50:二分查找法(折半查找法)

折半查找,也称二分查找,在某些情况下相比于顺序查找,使用折半查找算法的效率更高.但是该算法的使用的前提是静态查找表中的数据必须是有序的. 例如,在{5,21,13,19,37,75,56,64,88 ,80,92}这个查找表使用折半查找算法查找数据之前,需要首先对该表中的数据按照所查的关键字进行排序:{5,13,19,21,37,56,64,75,80,88,92}. 在折半查找之前对查找表按照所查的关键字进行排序的意思是:若查找表中存储的数据元素含有多个关键字时,使用哪种关键字做折半查找,就需

哈希容器

目录 hashtable 开链法 hashtable的桶子(buckets)与节点(nodes) haah table的图示 hashtable实现 hashtable的节点实现 hashtable的迭代器实现 hashfunction的设计 unordered_set hashtable 将一系列数放入容器中,将数除以内存的大小M,得到的余数挂在每个篮子下面.篮子的个数M一般取质数,当篮子所挂的链表长度大于篮子个数M时,就要rehashing,扩充篮子的数量(vector二倍扩充,不过扩充以后