溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

哈希表——開鏈法(哈希桶)

發(fā)布時間:2020-07-10 21:12:37 來源:網(wǎng)絡(luò) 閱讀:3099 作者:清幽寧 欄目:編程語言

   上篇博客我寫的是用線性探測來解決哈希表。http://10739316.blog.51cto.com/10729316/1771958

下面我在介紹另一種解決哈希表的方法,開鏈法,也叫哈希桶。下面我介紹一下這種方法的思路。

   基本思路:

    1.先給一個數(shù)組,這個數(shù)組中存的是指針數(shù)組,每個指針數(shù)組都指向一個數(shù)組。

    2.用元素除以存儲指針數(shù)組的數(shù)組的大小。

    3.余數(shù)與指針數(shù)組下標(biāo)相同的,都鏈到數(shù)組指針指向的這一個數(shù)組。

我在進(jìn)一步用圖表示一下:

哈希表——開鏈法(哈希桶)代碼如下:

HashTable.h中

#pragma once

#include <vector>
template<class K,class V>
struct HashTableNode
{
	K _key;
	V _value;
	HashTableNode* _next;
	HashTableNode(const K& key, const V& value)
		:_key(key)
		, _value(value)
		, _next(NULL)
	{}
};
template <class K,class V>
class HashTable
{
	typedef HashTableNode<K, V> Node;
public:
	//拷貝構(gòu)造
	HashTable()
		:_table(NULL)
		, _size(0)
	{}
	//拷貝構(gòu)造
	HashTable(const HashTable<K,V>& ht)
	{
		_table.resize(ht._table.size());
		for (int i = 0; i < ht._table.size(); i++)
		{
			Node* cur = ht._table[i];
			while (cur)
			{
				Node* tmp = new Node(cur->_key, cur->_value);
				tmp->_next = _table[i];
				_table[i] = tmp;
				_size++;
				cur = cur->_next;
			}
		}
	}
	//賦值運(yùn)算符的重載
	HashTable<K, V> operator=( HashTable<K, V> ht)
	{
		if (this != &ht)
		{
			swap(_table, ht._table);
			swap(_size, ht._size);
		}
		return *this;
	}
	//析構(gòu)函數(shù)
	~HashTable()
	{
		if (_table.size())
		{
			for (int i = 0; i < _table.size(); i++)
			{
				Node* cur = _table[i];
				while (cur)
				{
					Node* del = cur;
					cur = cur->_next;
					delete del;
					del = NULL;
				}
			}
		}
	}
	bool Insert(const K& key, const V& value)
	{
		//是否需要擴(kuò)容
		if (_size == _table.size())
		{
			_ExpandCapatity();
		}
		size_t index = _HashFunc(key);
		Node* cur = _table[index];
		//防冗余
		while (cur)
		{
			if (cur->_key == key)
			{
				return false;
			}
			cur = cur->_next;
		}
		//插入節(jié)點(diǎn)
		Node* tmp = new Node(key, value);
		tmp->_next = _table[index];
		_table[index] = tmp;
		_size++;
		return true;
	}
	Node* Find(const K& key)
	{
		size_t index = _HashFunc(key);
		Node* cur = _table[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 = _table[index];
		Node* prev = NULL;
		//找到要刪除的元素
		while (cur)
		{
			if (cur->_key == key)
			{
				break;
			}
			prev = cur;
			cur = cur->_next;
		}
		if (cur)
		{
			//頭刪
			if (cur == _table[index])
			{
				_table[index] = cur->_next;
			}
			//刪除中間元素
			else
			{
				Node* next = cur->_next;
				prev->_next = next;
			}
			delete cur;
			cur = NULL;
			_size--;
			return true;
		}
		return false;
	}
	void Print()
	{
		for (int i = 0; i < _table.size(); i++)
		{
			Node* cur = _table[i];
			cout << i << ":";
			while (cur)
			{
				cout << cur->_key << " ";
				cout << cur->_value << " ";
				cur = cur->_next;
			}
			if (_table[i] == NULL)
			{
				cout << "NULL";
			}
			cout <<endl;
		}
		cout << endl;
	}
protected:
	//算出應(yīng)該鏈接到哈希桶的那個位置
	size_t _HashFunc(const K& key)
	{
		return key%_table.size();
	}
	//新的容量
	size_t _NewSize()
	{
		// 使用素數(shù)表對齊做哈希表的容量,降低哈希沖突
		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]>_table.size())
			{
				return _PrimeList[i];//按照素數(shù)表來設(shè)置容量大小
			}
		}
		//當(dāng)需要的容量超過素數(shù)表的最大容量,我們就按照最大的來擴(kuò)容
		return _PrimeList[_PrimeSize - 1];
	}
	//哈希桶擴(kuò)張容量
	void _ExpandCapatity()
	{
		//開辟一個新的更大容量哈希桶
		size_t newsize = _NewSize();
		vector<Node*> newtable;
		newtable.resize(newsize);
		//把原來哈希桶中的元素再下來,插入到新的哈希桶
		for (int i = 0; i < _table.size(); i++)
		{
			Node* cur = _table[i];
			while (cur)
			{
				Node* tmp = cur;
				int index = _HashFunc(tmp->_key);
				//頭插法
				tmp->_next = newtable[index];
				newtable[index] = tmp;
				cur = cur->_next;
			}
			_table[i] = NULL;
		}
		_table.swap(newtable);
	}
protected:
	vector<Node*> _table;
	size_t _size;//數(shù)據(jù)的多少
};

     為了減少哈希沖突,我擴(kuò)張容量是用到了素數(shù)表。你們?nèi)绻雴栁覟槭裁从盟財?shù)表能減少哈希沖突,其實(shí)我也不知道,我只是知道別人這樣說,我拿來用而已。

//新的容量
	size_t _NewSize()
	{
		// 使用素數(shù)表對齊做哈希表的容量,降低哈希沖突
		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]>_table.size())
			{
				return _PrimeList[i];//按照素數(shù)表來設(shè)置容量大小
			}
		}
		//當(dāng)需要的容量超過素數(shù)表的最大容量,我們就按照最大的來擴(kuò)容
		return _PrimeList[_PrimeSize - 1];
	}
	//哈希桶擴(kuò)張容量
	void _ExpandCapatity()
	{
		//開辟一個新的更大容量哈希桶
		size_t newsize = _NewSize();
		vector<Node*> newtable;
		newtable.resize(newsize);
		//把原來哈希桶中的元素再下來,插入到新的哈希桶
		for (int i = 0; i < _table.size(); i++)
		{
			Node* cur = _table[i];
			while (cur)
			{
				Node* tmp = cur;
				int index = _HashFunc(tmp->_key);
				//頭插法
				tmp->_next = newtable[index];
				newtable[index] = tmp;
				cur = cur->_next;
			}
			_table[i] = NULL;
		}
		_table.swap(newtable);
	}

   希望自己的理解能幫到大家,如果有什么錯誤,希望大家及時提出,謝謝!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI