解决哈希冲突---开链法
更新:HHH   时间:2023-1-7


在上篇博客中,已经提出了两种解决哈希冲突的办法:线性探测,二次探测。

下面呢,在介绍一种解决冲突的办法---开链法(哈希桶)


哈希桶的实现:主要是将哈希冲突的那些值存到链表中。


代码实现:(支持字典查询)

#pragma once
#include <iostream>
#include <vector>
#include <string>

using namespace std;

template <class T,class V>
struct HashTableNode
{
	HashTableNode(const T& key,const V& value)
		:_key(key)
		,_value(value)
		,_next(NULL)
	{}
	T _key;
	V _value;
	HashTableNode<T,V>* _next;
};

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

template <>
struct __HashFunc<string>
{
	size_t operator()(const string& key)
	{
		size_t hash = 0;
		for(size_t i=0;i<key.size();++i)
		{
			hash += key[i];
		}
		return hash;
	}
};


template <class T,class V,class HashFunc = __HashFunc<T>>
class HashTableBucket   //哈希桶
{
	typedef HashTableNode<T,V> Node;
	typedef HashTableBucket<T,V,HashFunc> Table;
public:
	//构造
	HashTableBucket()
		:_table(NULL)
		,_size(0)
	{}
	HashTableBucket(size_t capacity)
		:_size(0)
	{
		_table.resize(_CheckCapacity(capacity));
	}
	//析构
	~HashTableBucket()
	{
		for(size_t i=0;i<_table.size();++i)
		{
			Node* cur = _table[i];
			while(cur)
			{
				Node* del = cur;
				cur = cur->_next;
				delete del;
			}
			_table[i] = NULL;
		}
	}
	//拷贝
	HashTableBucket(const Table& ht)
		:_size(0)
	{
		_table.resize(ht._table.size()); //开辟空间
		for(size_t i=0;i<ht._table.size();++i)
		{
			Node* cur = ht._table[i];
			while(cur)
			{
				Insert(cur->_key,cur->_value);
				cur = cur->_next;
			}
		}
	}
	//赋值
	/*HashTableBucket<T,V>& operator=(HashTableBucket<T,V> ht)
	{
		_table.swap(ht._table);
		swap(_size,ht._size);
		return *this;
	}*/

	Table& operator=(Table& ht)
	{
		if(this != &ht)
		{
			Table tmp(ht);
			_table.swap(tmp._table);
			swap(_size,tmp._size);
		}
		return *this;
	}
public:
	bool Insert(const T& key,const V& value)
	{
		_CheckCapacity();//检查容量
		size_t index = _HashFunc(key,_table.size());
		Node* cur = _table[index];
		while(cur)
		{
			if(cur->_key == key)  //防冗余
			{
				return false;
			}
			cur = cur->_next;
		}
		//头插
		Node* newNode =new Node(key,value);
		newNode->_next = _table[index];
		_table[index] = newNode;
		++_size;
		return true;
	}
	Node* Find(const T& key)
	{
		size_t index = _HashFunc(key,_table.size());
		Node* cur = _table[index];
		while(cur)
		{
			if(cur->_key == key)
			{
				return cur;
			}
			cur = cur->_next;
		}
		return NULL;
	}
	bool Remove(const T& key)
	{
		size_t index = _HashFunc(key,_table.size());
		Node* cur = _table[index];
		Node* prev = NULL;
		Node* del = NULL;
		if(cur->_key == key)
		{
			del = cur;
			_table[index] = cur->_next;
			delete del;
			return true;
		}	
		prev = cur;
		cur = cur->_next;
		while(cur)
		{
			if(cur->_key == key)
			{
				del = cur;
				prev->_next = cur->_next;
				delete del;
				return true;
			}
			prev = cur;
			cur = cur->_next;
		}
		return false;
	}
	void Print()
	{
		for(size_t i=0;i<_table.size();++i)
		{
			printf("_table[%d]:",i);
			Node* cur = _table[i];
			while(cur)
			{
				cout<<"["<<cur->_key<<","<<cur->_value<<"]"<<"->";
				cur = cur->_next;
			}
			cout<<"NULL"<<endl;
		}	
	}
protected:
	size_t _HashFunc(const T& key,size_t capacity) //哈希函数
	{
		//return key%capacity;
		HashFunc hash;
		return hash(key)%capacity;
	}
	size_t _GetNextPrime(const 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];
	}

	void _CheckCapacity()
	{
		if(_size == _table.size())
		{
			size_t nextPrime = _GetNextPrime(_size);
			vector<Node*> newtable;
			newtable.resize(nextPrime);
			for(size_t i=0;i<_table.size();++i)
			{
				Node* cur = _table[i];
				while(cur)
				{
					//摘节点
					Node* tmp = cur;
					cur = cur->_next;

					//计算在新表中的位置,头插
					size_t index = _HashFunc(tmp->_key,nextPrime);
					newtable[index] = tmp;
				}
				_table[i] = NULL;
			}
			_table.swap(newtable); //size,capacity,内容
		}
	}
private:
	vector<Node*> _table;  //哈希表
	size_t _size;          //数据的个数
};

测试代码:

#include "HashTableBucket.h"


void HashTableListTest()
{
	HashTableBucket<int,int> ht;
	for(size_t i=0;i<50;++i)
	{
		ht.Insert(i,i);
	}
	ht.Insert(107,32);
	ht.Insert(54,45);
	//ht.Insert(65,32);
	/*HashTableNode<int,int>* ret = ht.Find(1);
	if(ret)
	{
		cout<<"["<<ret->_key<<","<<ret->_value<<"]"<<endl;
	}*/
	//ht.Remove(54);
	ht.Remove(1);
	//ht.Print();
}

void HashTableTest()
{
	HashTableBucket<int,int> ht;
	ht.Insert(1,1);
	ht.Insert(11,11);
	ht.Insert(21,21);
	ht.Insert(12,12);
	ht.Insert(23,23);
	ht.Insert(54,57);
	ht.Insert(42,12);
	//ht.Print();
	HashTableBucket<int,int> ht1(ht);
	//ht1.Print();

	HashTableBucket<int,int> ht2;
	ht2 = ht1;
	ht2.Print();

}


void DircFindTest()
{
	HashTableBucket<string,string> ht;
	/*ht.Insert("zhang","张");
	ht.Insert("xiao","小");
	ht.Insert("yu","雨");*/
	//ht.Insert("angzh","田");

	ht.Insert("字典","dirc");
	ht.Insert("钱","money");
	ht.Insert("吃","eat");
	ht.Insert("玩","happy");
	ht.Print();
}


返回编程语言教程...