哈希表

哈希表:不同的Key值经过哈希函数Hash(Key)处理以后可能产生相同的值哈希地址,我们称这种情况为哈希冲突。所以用哈希冲突的开链法(哈希桶)进行处理,其结构如下:

wKiom1cx1Imzr3sxAAAjmbzKkKc289.png

代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
using namespace std;

template<class k,class v>
struct HashTableNode
{
	k _key;
	v _value;
	HashTableNode<k, v>* _next;
	
	HashTableNode<k,v>(const k& key, const v& value) //构造函数
		:_key(key)
		, _value(value)
		, _next(NULL)
	{}  
	 
	HashTableNode()    //构造无参函数
		:_key(0)
		, _value(0)
		, _next(NULL)
	{}
};

template<class k, class v>
class HashTable
{
	typedef HashTableNode<k, v> Node;
public:
	HashTable<k,v>()
		:_size(0)
		, _tables(NULL)
	{}

	HashTable<k,v>(const HashTable<k,v>& ht)  //拷贝构造函数
	{
		_tables.resize(ht._size);
		_size = ht._size;
		for (size_t i = 0; i < _size; i++)
		{
			Node* cur1 = ht._tables[i];
			Node* cur2 = NULL;
			
			while (cur1)
			{
				if (_tables[i] == NULL)
				{   //当链表为空,则开辟新节点,并将地址返回给_tables[i]
					_tables[i] = new Node(cur1->_key, cur1->_value);
					cur2 = _tables[i];
				}
				else
				{  //其他情况则将新开辟的节点地址返回给cur2的next
					cur2->_next = new Node(cur1->_key, cur1->_value);
				}
				cur1 = cur1->_next;
			}
		}
	}

	~HashTable()
	{
	    if (_size != 0)
		{
			for (size_t i = 0; i < _size; i++)
			{
				Node* del = _tables[i];
				while (del) //del不为空,则将del后的节点删除
				{
					Node* next = del->_next;
					delete del;
					del = next;
					_size--;
				}
				_tables[i] = NULL;
			}
		}
		
	}

	HashTable<k, v> &operator=(HashTable<k, v> ht)   //现代写法
	{   //函数传参时会构造一个对象,此时只需将对象中的_tables和_size相互交换就行了
             
		if (this != &ht)
		{
			if (&ht != this)
			{
				swap(_tables, ht._tables);
				swap(_size, ht._size);
			}
			return *this; 

		}
	}
		
	
	bool Insert(const k& key, const v& value)
	{
		if (_size == _tables.size())
		{
			_CheckExpand();  //先进行检查容量,如若不够则需扩容
		}
		
		size_t index = _HashFunc(key); //将下标赋值给index
		Node* begin = _tables[index];
		while (begin)
		{
			if (begin->_key == key)
			{
				return false; //查找key,如若有则返回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)  //返回key所在的下标
	{
		return key%_tables.size();
	}

	void _CheckExpand()   //检查扩容
	{
		
			size_t newsize = _GetNextPrime();
			if (newsize == _size)//若果当前容量等于newsize,函数返回
			{
				return;
			}
	
			vector<Node*> newTables;
			newTables.resize(newsize); //开辟newsize大小的容量
			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);
					tmp->_next = newTables[index];
					newTables[index] = tmp;
				}
				_tables[i] =NULL;
			}
			_tables.swap(newTables);
	}

	size_t  _GetNextPrime()  //定义28个素数表,因为素数有利于降低载荷因子
	{
		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 (int i = 0; i < _PrimeSize; i++)
		{
			if (_PrimeList[i]> _tables.size())
			{
				return _PrimeList[i];
			}
		}
		return _PrimeList[_PrimeSize - 1];
	}

	Node* Find(const k& key)     //查找节点 并返回该节点地址
	{
		size_t index = _HashFunc(key);
		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);
		Node* cur = _tables[index];
		Node* prev = NULL;
		while (cur)
		{
			if (cur->_key == key)
			{
				break;
			}
			prev = cur;
			cur = cur->_next;
		}
		if (cur == _tables[index])
		{
			_tables[index] = cur->_next;
			return true;
		}

		else
		{
			prev->_next = cur->_next;
			delete cur;
			return true;
		}
		return false;
	}

	void PrintTables()
	{
		printf("哈希表如下:\n");
		for (size_t i = 0; i < _tables.size(); i++)
		{
			Node* cur = _tables[i];
			while (cur)
			{ 
				/*cout << cur->_key << " ";
				cur = cur->_next;*/
				
				printf("[%d]=%c & %d  ", i, cur->_value,cur->_key);
				cur = cur->_next;
				if (cur==NULL)
				{
					printf("\n");
				}
			}
		}
		printf("\n");
	}

protected:
	size_t _size;
	vector<Node*> _tables;
};

测试代码如下:
void Test()
{
   typedef HashTableNode<int, char> Node;

    HashTable<int, char> ht;
	ht.Insert(1, 'a');
	ht.Insert(2, 'b');
	ht.Insert(3, 'c');
	ht.Insert(4, 'd');
	ht.Insert(5, 'e');
	ht.Insert(54, 'x');
	ht.Insert(55, 'y');
	ht.Insert(56, 'z');
	ht.PrintTables();

	HashTable<int, char> ht2;
	ht2.Insert(54, 'x');
	ht2.Insert(55, 'y');
	ht2.Insert(56, 'z');
	ht2.Insert(1, 'a');
	ht2.Insert(2, 'b');
	ht2.Insert(3, 'c');
	ht2.Insert(4, 'd');
	ht2.Insert(5, 'e');
	ht2.PrintTables();

	
	ht=ht2;
	ht.PrintTables();



	/*Node* ret = ht.Find(55);
	cout << ret->_value << endl;*/
	/*ht.Remove(4);
	ht.PrintTables();*/
	

	/*HashTable<int, char> ht1(ht);
	ht1.PrintHashTable();*/
}


int main()
{
	Test();
	system("pause");
	return 0;
}


本文出自 “零点时光” 博客,请务必保留此出处http://10741764.blog.51cto.com/10731764/1771939

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值