国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

改造哈希表,封裝unordered_map和unordered_set

這篇具有很好參考價值的文章主要介紹了改造哈希表,封裝unordered_map和unordered_set。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

正文開始前給大家推薦個網(wǎng)站,前些天發(fā)現(xiàn)了一個巨牛的人工智能學(xué)習(xí)網(wǎng)站,通俗易懂,風(fēng)趣幽默,忍不住分享一下給大家。點(diǎn)擊跳轉(zhuǎn)到網(wǎng)站。

unordered_map是存的是pair是K,V型的,而unordered_set是K型的,里面只存一個值,那我們?nèi)绾卫靡粋€數(shù)據(jù)結(jié)構(gòu)將他們都封裝出來呢?

我們知道哈希表我們實(shí)現(xiàn)的是存pair的,我們可以使用最笨的方法直接復(fù)制一份,把存pair的改為存Key的,但是我們可以參考一下大佬的做法,大佬直接把存的東西弄成一個模版參數(shù),這個東西具體存的啥由用戶來決定,用戶傳什么就存什么,所以改造后的哈希表的第二個類型模版參數(shù)就是我們要存的類型!

template <class T>
struct HashNode
{
	T _data;
	HashNode* _next;

	HashNode(const T& data)
		: _data(data)
		, _next(nullptr)
	{}
};
template <class K, class V,class KeyOfT, class Hash = HashFunc<K>>
class HashTable
{
	typedef HashNode<V> Node;
private:
	KeyOfT kt;
	vector<Node*> _tables;
	size_t _n = 0;
	Hash hs;
};

我們可以看到V是什么類型,那么這個哈希表中存的就是什么,但是會有下一個問題,我們在取余時,不管是unordered_map還是unordered_set都是對Key取余,但是這里我們不知道他是Key還是pair,那怎么辦呢?

我們可以通過仿函數(shù)解決這個問題,我們每個需要用Key計(jì)算的地方都走一層仿函數(shù),然后unordered_set的就直接返回key就行,unordered_map則需要返回pair的first。我們會看到上面的結(jié)果多了個KeyOfT的模版,這個就是返回Key的仿函數(shù)。

unordered_map

template<class K, class V>
class unordered_map
{
	struct MapKOfT
	{
		const K& operator()(const pair<const K, V>& kv)
		{
			return kv.first;
		}
	};
	private:
	hash_bucket::HashTable<K, pair<K,V>,MapKOfT> _ht;
};

unordered_set

template<class K>
class unordered_set
{
	struct SetKOfT
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};
		private:
	hash_bucket::HashTable<K, K,SetKOfT> _ht;
};

至此我們最簡單的框架就搭建出來了。需要注意的是所有需要用Key的地方都要走一層仿函數(shù)。
插入刪除什么的直接復(fù)用哈希表的就可以,就下來主要就是實(shí)現(xiàn)迭代器。

迭代器

迭代器的結(jié)構(gòu)應(yīng)該是什么樣子的?
節(jié)點(diǎn)的指針肯定是必須的,但是如果我們當(dāng)前的桶走完了,如何++到下一個桶呢?
所以我們需要這張哈希表,用來找當(dāng)前桶走完以后的下一個桶。這里不傳這張哈希表也是可以的,因?yàn)槲覀兊哪康氖钦蚁乱粋€桶,所以把哈希表中的vector傳過來也是可以的。

那么迭代器如何++呢?

如果他的下一個節(jié)點(diǎn)是空,那么就說明這個桶走完了,我們需要找下一個桶,所以我們需要當(dāng)前的位置,所以我們可以直接把當(dāng)前桶的位置傳過來,也可以當(dāng)場計(jì)算桶的位置,這兩種方法都是可以的,但是如果這張表走完了還沒找到下一個桶,那就說明這張表走完了,我們直接把節(jié)點(diǎn)的指針改為nullptr即可。
如果它的下一個節(jié)點(diǎn)不為空,那直接讓它等于它的next即可。

const的迭代器我們可以和之前一樣,直接用兩個模版參數(shù)來決定它是普通迭代器還是const迭代器。

template <class K, class V,class Ref, class Ptr, class KeyOfT, class Hash = HashFunc<K>>
struct __HTIterator
{
	typedef HashNode<V> Node;
	typedef __HTIterator<K, V,Ref,Ptr, KeyOfT, Hash> Self;

	Node* _node;
	const HashTable<K, V, KeyOfT, Hash>* _pht;
	size_t hashi;
	__HTIterator(Node* node,const HashTable<K, V, KeyOfT, Hash>* pht,size_t i)
		: _node(node)
		, _pht(pht)
		, hashi(i)
	{}


	Self operator++()
	{
		if (_node->_next)
		{
			_node = _node->_next;
		}
		else
		{
			++hashi;
			while (hashi < _pht->_tables.size())
			{
				if (_pht->_tables[hashi])
				{
					_node = _pht->_tables[hashi];
					break;
				}
				++hashi;
			}
			if (hashi == _pht->_tables.size())
			{
				_node = nullptr;
			}
		}

		return *this;
	}

	bool operator!= (const Self& s)
	{
		return _node != s._node;
	}

	bool operator== (const Self& s)
	{
		return _node == s._node;
	}

	Ref operator*()
	{
		return _node->_data;
	}

	Ptr operator->()
	{
		return &(_node->_data);
	}
};

但是這里會有一個相互依賴的問題,就是哈希表需要用迭代器,迭代器需要用哈希表,如果哈希表在前面我們就需要前置聲明一下迭代器,迭代器同理,我們需要在前面聲明一個哈希表,但是解決完這個問題以后還存在一個問題,就是哈希表中的vector是私有成員,迭代器不能直接訪問,所以我們需要把迭代器聲明為哈希表的友元。
改造哈希表,封裝unordered_map和unordered_set,C++,數(shù)據(jù)結(jié)構(gòu)與算法,散列表,哈希算法,數(shù)據(jù)結(jié)構(gòu)

改造哈希表,封裝unordered_map和unordered_set,C++,數(shù)據(jù)結(jié)構(gòu)與算法,散列表,哈希算法,數(shù)據(jù)結(jié)構(gòu)
把迭代器實(shí)現(xiàn)好以后,接下來就是解決Key不能修改的問題。
unordeted_set和unordeted_map如何實(shí)現(xiàn)Key不能修改呢?
我們通過觀察原碼會發(fā)現(xiàn)unordeted_set迭代器和const迭代器都是const迭代器,它是通過這樣的方式來實(shí)現(xiàn)的。unordeted_map是Key不能修改而Value是可以修改的,所以它的pair是pair<const K,V>它把Key設(shè)置為const,這樣就能夠保證Key不能修改,Value可以修改。

接下來需要實(shí)現(xiàn)的是unordered_map的[]重載,要實(shí)現(xiàn)這個重載我們就需要對哈希表的插入進(jìn)行修改,它的返回值不能再是一個bool值,而是一個pair,這個pair的first是iterator迭代器,second是bool類型代表是否插入成功。改造完以后,就可以實(shí)現(xiàn)[]重載,但是對應(yīng)容器的插入的返回值也需要變一下,[]重載主要就是存在就插入不存在就不插入,但是都會返回Val的是可以別被我們修改。

當(dāng)改造完插入以后,我們會發(fā)現(xiàn)unordered_set的插入編譯編不過,這是因?yàn)閡nordered_set的迭代器都是const迭代器,而哈希表的插入返回的是普通的迭代器,這里的iterator無法轉(zhuǎn)化為const_iterator,所以編譯錯誤,有兩種方式可以解決,我們可以支持const迭代器轉(zhuǎn)化為普通迭代器,我們也可以直接用const中的東西來構(gòu)造新的普通迭代器。此時我們的封裝差不多就完善了。

改造后的哈希表

namespace hash_bucket
{
	template <class T>
	struct HashNode
	{
		T _data;
		HashNode* _next;

		HashNode(const T& data)
			: _data(data)
			, _next(nullptr)
		{}
	};

	template <class K, class V, class KeyOfT, class Hash>
	class HashTable;

	template <class K, class V,class Ref, class Ptr, class KeyOfT, class Hash = HashFunc<K>>
	struct __HTIterator
	{
		typedef HashNode<V> Node;
		typedef __HTIterator<K, V,Ref,Ptr, KeyOfT, Hash> Self;

		Node* _node;
		const HashTable<K, V, KeyOfT, Hash>* _pht;
		size_t hashi;
		__HTIterator(Node* node,const HashTable<K, V, KeyOfT, Hash>* pht,size_t i)
			: _node(node)
			, _pht(pht)
			, hashi(i)
		{}


		Self operator++()
		{
			if (_node->_next)
			{
				_node = _node->_next;
			}
			else
			{
				++hashi;
				while (hashi < _pht->_tables.size())
				{
					if (_pht->_tables[hashi])
					{
						_node = _pht->_tables[hashi];
						break;
					}
					++hashi;
				}
				if (hashi == _pht->_tables.size())
				{
					_node = nullptr;
				}
			}

			return *this;
		}

		bool operator!= (const Self& s)
		{
			return _node != s._node;
		}

		bool operator== (const Self& s)
		{
			return _node == s._node;
		}

		Ref operator*()
		{
			return _node->_data;
		}

		Ptr operator->()
		{
			return &(_node->_data);
		}
	};

	template <class K, class V,class KeyOfT, class Hash = HashFunc<K>>
	class HashTable
	{
		typedef HashNode<V> Node;

		template <class K, class V,class Ref, class Ptr, class KeyOfT, class Hash>
		friend struct __HTIterator;

	public:
		typedef __HTIterator<K, V, V&, V*, KeyOfT, Hash> iterator;
		typedef __HTIterator<K, V, const V&,const V*,KeyOfT, Hash> const_iterator;

		iterator begin()
		{
			for (size_t i = 0; i < _tables.size(); i++)
			{
				if (_tables[i])
				{
					return iterator(_tables[i], this, i);
				}
			}
			return end();
		}

		iterator end()
		{
			return iterator(nullptr, this, -1);
		}

		const_iterator begin() const
		{
			for (size_t i = 0; i < _tables.size(); i++)
			{
				if (_tables[i])
				{
					return const_iterator(_tables[i], this, i);
				}
			}
			return end();
		}

		const_iterator end() const
		{
			return const_iterator(nullptr, this, -1);
		}
		HashTable()
		{
			_tables.resize(10);
		}

		~HashTable()
		{
			for (size_t i = 0; i < _tables.size(); i++)
			{
				Node* cur = _tables[i];
				while (cur)
				{
					Node* next = cur->_next;
					delete cur;
					cur = next;
				}
				_tables[i] = nullptr;
			}
		}
		pair<iterator,bool> Insert(const V& data)
		{
			iterator ret = Find(kt(data));
			if (ret!=end())
			{
				return make_pair(ret,false);
			}

			if (_n == _tables.size())
			{
				//需要擴(kuò)容
				vector<Node*> newtables;
				newtables.resize(2 * _tables.size());

				for (size_t i = 0; i < _tables.size(); i++)
				{
					Node* cur = _tables[i];
					while (cur)
					{
						Node* next = cur->_next;
						size_t hashi = hs(kt(cur->_data))% newtables.size();
						cur->_next = newtables[hashi];
						newtables[hashi] = cur;

						cur = next;
					}
					_tables[i] = nullptr;
				}

				_tables.swap(newtables);
			}

			size_t hashi = hs(kt(data)) % _tables.size();
			Node* cur = new Node(data);
			cur->_next = _tables[hashi];
			_tables[hashi] = cur;
			_n++;
			return make_pair(iterator(cur,this,hashi), true);
		}

		//__HTIterator<K, V, V&, V*, KeyOfT, Hash>
		// __HTIterator<K, V,Ref,Ptr, KeyOfT, Hash>
		iterator Find(const K& k)
		{
			size_t hashi = hs(k) % _tables.size();
			Node* cur = _tables[hashi];
			while (cur)
			{
				if (kt(cur->_data) == k)
				{
					return iterator(cur,this,hashi);
				}

				cur = cur->_next;
			}

			return end();
		}

		bool Erase(const K& k)
		{
			size_t hashi = hs(k) % _tables.size();

			Node* cur = _tables[hashi];
			Node* prev = nullptr;
			while (cur)
			{
				if (cur->_kv.first == k)
				{
					if (prev==nullptr)
					{
						_tables[hashi] = cur->_next;
					}
					else
					{
						prev->_next = cur->_next;
					}
					delete cur;
					return true;
				}
				cur = cur->_next;
			}

			return false;
		}
	private:
		KeyOfT kt;
		vector<Node*> _tables;
		size_t _n = 0;
		Hash hs;
	};
}

封裝的unordered_map

template<class K, class V>
	class unordered_map
	{
		struct MapKOfT
		{
			const K& operator()(const pair<const K, V>& kv)
			{
				return kv.first;
			}
		};
	public:
		typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKOfT>::iterator iterator;
		typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKOfT>::const_iterator const_iterator;

		iterator begin()
		{
			return _ht.begin();
		}

		iterator end()
		{
			return _ht.end();
		}

		const_iterator begin() const
		{
			return _ht.begin();
		}

		const_iterator end() const
		{
			return _ht.end();
		}

		pair<iterator, bool> insert(const pair<K, V>& kv)
		{
			return _ht.Insert(kv);
		}

		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));

			return ret.first->second;
		}
	private:
		hash_bucket::HashTable<K, pair<const K,V>,MapKOfT> _ht;
	};

封裝的unordered_set文章來源地址http://www.zghlxwxcb.cn/news/detail-771179.html

template<class K>
class unordered_set
{
	struct SetKOfT
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};
public:
	typedef typename hash_bucket::HashTable<K, K, SetKOfT>::const_iterator iterator;
	typedef typename hash_bucket::HashTable<K, K, SetKOfT>::const_iterator const_iterator;

	iterator begin() const 
	{
		return _ht.begin();
	}

	iterator end() const
	{
		return _ht.end();
	}

	pair<iterator, bool> insert(const K& key)
	{
		auto ret = _ht.Insert(key);
		return make_pair(iterator(ret.first._node, ret.first._pht,ret.first.hashi), ret.second);
	}

private:
	hash_bucket::HashTable<K, K,SetKOfT> _ht;
};

到了這里,關(guān)于改造哈希表,封裝unordered_map和unordered_set的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • C++STL詳解(十) -- 使用哈希表封裝unordered_set和unordered_map

    C++STL詳解(十) -- 使用哈希表封裝unordered_set和unordered_map

    因?yàn)椴煌萜鞯念愋筒煌?如果是unordered_map,V代表一個鍵值對,如果unordered_set,V代表Key值,而底層哈希表并不知道上層容器所要傳遞的V模板參數(shù)類型,為了與哈希表的模板參數(shù)區(qū)分,我們將哈希表中的V模板參數(shù)改為T. 例如: 在哈希表中當(dāng)我們使用Find函數(shù)進(jìn)行查找時: 如果上層傳遞的

    2024年02月01日
    瀏覽(38)
  • 【C++】STL——用一個哈希表封裝出unordered_map和unordered_set

    【C++】STL——用一個哈希表封裝出unordered_map和unordered_set

    根據(jù)先前對unordered_map和unordered_set的學(xué)習(xí),我們得知其底層是借助哈希表來實(shí)現(xiàn)的,接下來我們會使用上篇博客實(shí)現(xiàn)的開散列哈希表來模擬實(shí)現(xiàn)unordered_map和unordered_set,哈希表源代碼鏈接: Hash/Hash/HashBucket.h · wei/cplusplus - 碼云 - 開源中國 (gitee.com) 下面我們對哈希表進(jìn)行改造,

    2023年04月18日
    瀏覽(26)
  • 從C語言到C++_31(unordered_set和unordered_map介紹+哈希桶封裝)

    從C語言到C++_31(unordered_set和unordered_map介紹+哈希桶封裝)

    目錄 1.?unordered_set和unordered_map 1.1?unordered_map 1.2?unordered_set 1.3 unordered系列寫OJ題 961. 在長度 2N 的數(shù)組中找出重復(fù) N 次的元素 - 力扣(LeetCode) 349. 兩個數(shù)組的交集 - 力扣(LeetCode) 217. 存在重復(fù)元素 - 力扣(LeetCode) 884. 兩句話中的不常見單詞 - 力扣(LeetCode) 2. 實(shí)現(xiàn)unorder

    2024年02月13日
    瀏覽(14)
  • 【C++學(xué)習(xí)】哈希表的底層實(shí)現(xiàn)及其在unordered_set與unordered_map中的封裝

    【C++學(xué)習(xí)】哈希表的底層實(shí)現(xiàn)及其在unordered_set與unordered_map中的封裝

    ??個人名片: ??作者簡介:一名樂于分享在學(xué)習(xí)道路上收獲的大二在校生 ??個人主頁??:GOTXX ??個人WeChat:ILXOXVJE ??本文由GOTXX原創(chuàng),首發(fā)CSDN?????? ??系列專欄:零基礎(chǔ)學(xué)習(xí)C語言----- 數(shù)據(jù)結(jié)構(gòu)的學(xué)習(xí)之路----C++的學(xué)習(xí)之路 ??每日一句:如果沒有特別幸運(yùn),那就請?zhí)?/p>

    2024年04月16日
    瀏覽(38)
  • 封裝unordered_set&&unordered_map

    注:實(shí)現(xiàn)unordered系列容器是為了學(xué)習(xí),因此并非將全部接口實(shí)現(xiàn),所以只實(shí)現(xiàn)部分接口 目錄 哈希表的改造 模板參數(shù)列表的改造 增加迭代器操作 增加通過T獲取value操作 HashTable.h的修改 unordered_set的封裝 unordered_map的封裝 K:關(guān)鍵碼類型 T:不同容器T的類型不同,如果是unorder

    2024年02月05日
    瀏覽(33)
  • 【unordered_map和unordered_set的封裝】

    這里的思路與前面講解map/set的封裝思路一致,STL不喜歡直接實(shí)例化出兩份幾乎相同的代碼,所以用了模板參數(shù)來處理,還是老規(guī)矩: set中傳入的是K,K,map中傳入的是K,PairK,V .這樣我們在哈希桶的結(jié)構(gòu)中只需要用一個T類型的模板參數(shù)接受上層傳入的參數(shù)即可。 基本框架的改造:

    2024年02月08日
    瀏覽(22)
  • 【C++】用哈希桶模擬實(shí)現(xiàn)unordered_set和unordered_map

    【C++】用哈希桶模擬實(shí)現(xiàn)unordered_set和unordered_map

    順序結(jié)構(gòu)中(數(shù)組)查找一個元素需要遍歷整個數(shù)組,時間復(fù)雜度為O(N);樹形結(jié)構(gòu)中(二叉搜索樹)查找一個元素,時間復(fù)雜度最多為樹的高度次logN。理想的搜索方法: 可以不經(jīng)過任何比較,一次直接從表中得到要搜索的元素。 構(gòu)造一種存儲結(jié)構(gòu), 通過某種函數(shù)使元素的

    2024年04月11日
    瀏覽(21)
  • 從哈希桶角度看 unordered_map 與 unordered_set 的實(shí)現(xiàn)

    哈希函數(shù)與哈希桶是計(jì)算機(jī)科學(xué)中用于實(shí)現(xiàn)高效數(shù)據(jù)檢索的重要工具。在之前的博客中,我們已經(jīng)詳細(xì)探討了哈希的基本概念、哈希函數(shù)的構(gòu)造方法以及哈希桶的工作原理等內(nèi)容。在本篇博客中,我們將進(jìn)一步深入探索C++中的unordered系列數(shù)據(jù)結(jié)構(gòu),并利用之前介紹的哈希桶原

    2024年03月22日
    瀏覽(20)
  • 【C++】unordered_set與unordered_map的封裝

    【C++】unordered_set與unordered_map的封裝

    ??個人主頁:平凡的小蘇 ??學(xué)習(xí)格言:命運(yùn)給你一個低的起點(diǎn),是想看你精彩的翻盤,而不是讓你自甘墮落,腳下的路雖然難走,但我還能走,比起向陽而生,我更想嘗試逆風(fēng)翻盤 。 ?? C++專欄 : C++內(nèi)功修煉基地 家人們更新不易,你們的??點(diǎn)贊??和?關(guān)注?真的對我真

    2024年02月08日
    瀏覽(23)
  • 【C++】unordered_set 和 unordered_map 使用 | 封裝

    【C++】unordered_set 和 unordered_map 使用 | 封裝

    unordered_map官方文檔 unordered_set 官方文檔 set / map與unordered_set / unordered_map 使用功能基本相同,但是兩者的底層結(jié)構(gòu)不同 set/map底層是紅黑樹 unordered_map/unordered_set 底層是 哈希表 紅黑樹是一種搜索二叉樹,搜索二叉樹又稱為排序二叉樹,所以 迭代器遍歷是有序的 而哈希表對應(yīng)的

    2024年02月06日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包