tinystl实现(第二十一步:散列表实现)

39 篇文章 4 订阅
28 篇文章 36 订阅

经过长时间的学习终于可以开始tinystl的仿(chao)写工作了,本文参考了这位大神的github,坦白讲我只是补充了注释,因为tinystl的代码真的非常经典而我又没什么这种大型项目的经验,所以只能这样做,不过相信能够有助于大家的学习
#强烈建议按顺序阅读本专栏
散列表,哈希表都是容器中的重要内容,虽然本篇中并没有哈希函数这一关键步骤(关键在于难以找到放之四海而皆准的映射方法),但是其内涵依旧有趣
.h文件:

#pragma once
#ifndef _UNORDERED_SET_H_
#define _UNORDERED_SET_H_
#include "Allocator.h"
#include "Algorithm.h"
#include "Functional.h"
#include "Iterator.h"
#include "List.h"
#include "Vector.h"

namespace mySTL {
	template<class Key, class Hash, class KeyEqual, class Allocator>
	class Unordered_set;
	namespace Detail {
		template<class Key, class ListIterator, class Hash = std::hash<Key>,
			class KeyEqual = mySTL::equal_to<Key>, class Allocator = mySTL::allocator < Key >>
			class ust_iterator : public iterator<forward_iterator_tag, Key> {
			private:
				template<class Key, class Hash, class KeyEqual, class Allocator>
				friend class Unordered_set;
			private:
				typedef Unordered_set<Key, Hash, KeyEqual, Allocator>* cntrPtr;
				size_t bucket_index_;
				ListIterator iterator_;
				cntrPtr container_;
			public:
				ust_iterator(size_t index, ListIterator it, cntrPtr ptr);
				ust_iterator& operator ++();
				ust_iterator operator ++(int);
				Key& operator*() { return *iterator_; }
				Key* operator->() { return &(operator*()); }
			private:
				template<class Key, class ListIterator, class Hash, class KeyEqual, class Allocator>
				friend bool operator ==(const ust_iterator<Key, ListIterator, Hash, KeyEqual, Allocator>& lhs,
					const ust_iterator<Key, ListIterator, Hash, KeyEqual, Allocator>& rhs);
				template<class Key, class ListIterator, class Hash, class KeyEqual, class Allocator>
				friend bool operator !=(const ust_iterator<Key, ListIterator, Hash, KeyEqual, Allocator>& lhs,
					const ust_iterator<Key, ListIterator, Hash, KeyEqual, Allocator>& rhs);
		};
	}//end of namespace Detail


	template<class Key, class Hash = std::hash<Key>,
		class KeyEqual = mySTL::equal_to<Key>, class Allocator = mySTL::allocator < Key >>
		class Unordered_set {
		private:
			template<class Key, class ListIterator, class Hash, class KeyEqual, class Allocator>
			friend class Detail::ust_iterator;
		public:
			typedef Key key_type;
			typedef Key value_type;
			typedef size_t size_type;
			typedef Hash haser;
			typedef KeyEqual key_equal;
			typedef Allocator allocator_type;
			typedef value_type& reference;
			typedef const value_type& const_reference;
			typedef typename mySTL::list<key_type>::iterator local_iterator;
			typedef Detail::ust_iterator<Key, typename mySTL::list<key_type>::iterator, Hash, KeyEqual, Allocator> iterator;
		private:
			mySTL::vector<mySTL::list<key_type>> buckets_;
			size_type size_;
			float max_load_factor_;
#define PRIME_LIST_SIZE 28
			static size_t prime_list_[PRIME_LIST_SIZE];
		public:
			explicit Unordered_set(size_t bucket_count);
			template<class InputIterator>
			Unordered_set(InputIterator first, InputIterator last);
			Unordered_set(const Unordered_set& ust);
			Unordered_set& operator = (const Unordered_set& ust);

			size_type size()const;
			bool empty()const;
			size_type bucket_count()const;
			size_type bucket_size(size_type i)const;
			size_type bucket(const key_type& key)const;
			float load_factor()const;
			float max_load_factor()const;
			void max_load_factor(float z);
			void rehash(size_type n);

			iterator begin();
			iterator end();
			local_iterator begin(size_type i);
			local_iterator end(size_type i);

			iterator find(const key_type& key);
			size_type count(const key_type& key);

			mySTL::pair<iterator, bool> insert(const value_type& val);
			template<class InputIterator>
			void insert(InputIterator first, InputIterator last);
			iterator erase(iterator position);
			size_type erase(const key_type& key);

			haser hash_function()const;
			key_equal key_eq()const;
			allocator_type get_allocator()const;
		private:
			size_type next_prime(size_type n)const;
			size_type bucket_index(const key_type& key)const;
			bool has_key(const key_type& key);
		public:
			template<class Key, class Hash, class KeyEqual, class Allocator>
			friend void swap(Unordered_set<Key, Hash, KeyEqual, Allocator>& lhs,
				Unordered_set<Key, Hash, KeyEqual, Allocator>& rhs);
	};
}
#include "Detail\Unordered_set.impl.h"
#endif // !_UNORDERED_SET_H_

Unordered_set.impl.h

#pragma once
#ifndef _UNORDERED_SET_IMPL_H_
#define _UNORDERED_SET_IMPL_H_
#include <functional>//for bind
namespace mySTL {
	namespace Detail {
		template<class Key, class ListIterator, class Hash, class KeyEqual, class Allocator>
		ust_iterator<Key, ListIterator, Hash, KeyEqual, Allocator>::ust_iterator(size_t index, ListIterator it, cntrPtr ptr)
			:bucket_index_(index), iterator_(it), container_(ptr) {}
		template<class Key, class ListIterator, class Hash, class KeyEqual, class Allocator>
		ust_iterator<Key, ListIterator, Hash, KeyEqual, Allocator>&
			ust_iterator<Key, ListIterator, Hash, KeyEqual, Allocator>::operator ++() {
			++iterator_;
			//如果前进一位后到达了list的末尾,则需要跳转到下一个有item的bucket的list
			if (iterator_ == container_->buckets_[bucket_index_].end()) {
				for (;;) {
					if (bucket_index_ == container_->buckets_.size() - 1) {
						*this = container_->end();
						break;
					}
					else {
						++bucket_index_;
						if (!(container_->buckets_[bucket_index_].empty())) {//此list不为空
							iterator_ = container_->buckets_[bucket_index_].begin();
							break;
						}
					}
				}
			}
			return *this;
		}
		template<class Key, class ListIterator, class Hash, class KeyEqual, class Allocator>
		ust_iterator<Key, ListIterator, Hash, KeyEqual, Allocator>
			ust_iterator<Key, ListIterator, Hash, KeyEqual, Allocator>::operator ++(int) {
			auto res = *this;
			++*this;
			return res;
		}
		template<class Key, class ListIterator, class Hash, class KeyEqual, class Allocator>
		bool operator ==(const ust_iterator<Key, ListIterator, Hash, KeyEqual, Allocator>& lhs,
			const ust_iterator<Key, ListIterator, Hash, KeyEqual, Allocator>& rhs) {
			return lhs.bucket_index_ == rhs.bucket_index_ &&
				lhs.iterator_ == rhs.iterator_ &&
				lhs.container_ == rhs.container_;
		}
		template<class Key, class ListIterator, class Hash, class KeyEqual, class Allocator>
		bool operator !=(const ust_iterator<Key, ListIterator, Hash, KeyEqual, Allocator>& lhs,
			const ust_iterator<Key, ListIterator, Hash, KeyEqual, Allocator>& rhs) {
			return !(lhs == rhs);
		}
	}
	template<class Key, class Hash, class KeyEqual, class Allocator>
	typename Unordered_set<Key, Hash, KeyEqual, Allocator>::size_type
		Unordered_set<Key, Hash, KeyEqual, Allocator>::size()const {
		return size_;
	}
	template<class Key, class Hash, class KeyEqual, class Allocator>
	bool Unordered_set<Key, Hash, KeyEqual, Allocator>::empty()const {
		return size() == 0;
	}
	template<class Key, class Hash, class KeyEqual, class Allocator>
	typename Unordered_set<Key, Hash, KeyEqual, Allocator>::size_type
		Unordered_set<Key, Hash, KeyEqual, Allocator>::bucket_count()const {
		return buckets_.size();
	}
	template<class Key, class Hash, class KeyEqual, class Allocator>
	typename Unordered_set<Key, Hash, KeyEqual, Allocator>::size_type
		Unordered_set<Key, Hash, KeyEqual, Allocator>::bucket_size(size_type i)const {
		return buckets_[i].size();
	}
	template<class Key, class Hash, class KeyEqual, class Allocator>
	typename Unordered_set<Key, Hash, KeyEqual, Allocator>::size_type
		Unordered_set<Key, Hash, KeyEqual, Allocator>::bucket(const key_type& key)const {
		return bucket_index(key);
	}
	template<class Key, class Hash, class KeyEqual, class Allocator>
	float Unordered_set<Key, Hash, KeyEqual, Allocator>::load_factor()const {
		return (float)size() / (float)bucket_count();
	}
	template<class Key, class Hash, class KeyEqual, class Allocator>
	typename Unordered_set<Key, Hash, KeyEqual, Allocator>::haser
		Unordered_set<Key, Hash, KeyEqual, Allocator>::hash_function()const {
		return haser();
	}
	template<class Key, class Hash, class KeyEqual, class Allocator>
	typename Unordered_set<Key, Hash, KeyEqual, Allocator>::key_equal
		Unordered_set<Key, Hash, KeyEqual, Allocator>::key_eq()const {
		return key_equal();
	}
	template<class Key, class Hash, class KeyEqual, class Allocator>
	typename Unordered_set<Key, Hash, KeyEqual, Allocator>::allocator_type
		Unordered_set<Key, Hash, KeyEqual, Allocator>::get_allocator()const {
		return allocator_type();
	}
//将表格的大小设置为质数,然后直接使用保留余数法求哈希值
//按照SGI STL中的原则,首先保存28个质数(逐渐呈现大约2倍的关系)
//同时提供一个函数,用来查询在这28个质数中,最接近某数并大于某数的质数
	template<class Key, class Hash, class KeyEqual, class Allocator>
	size_t Unordered_set<Key, Hash, KeyEqual, Allocator>::prime_list_[PRIME_LIST_SIZE] = {
		53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, 196613, 393241,
		786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611,
		402653189, 805306457, 1610612741, 3221225473, 4294967291,
	};
	template<class Key, class Hash, class KeyEqual, class Allocator>
	bool Unordered_set<Key, Hash, KeyEqual, Allocator>::has_key(const key_type& key) {
		auto& list = buckets_[bucket_index(key)];//找到对应桶
		auto pred = std::bind(KeyEqual(), key, std::placeholders::_1);
		return mySTL::find_if(list.begin(), list.end(), pred) != list.end();//查找list
	}
	template<class Key, class Hash, class KeyEqual, class Allocator>
	typename Unordered_set<Key, Hash, KeyEqual, Allocator>::size_type
		Unordered_set<Key, Hash, KeyEqual, Allocator>::bucket_index(const key_type& key)const {
		return haser()(key) % buckets_.size();//通过哈希映射找到对应块
	}
	template<class Key, class Hash, class KeyEqual, class Allocator>
	typename Unordered_set<Key, Hash, KeyEqual, Allocator>::size_type
		Unordered_set<Key, Hash, KeyEqual, Allocator>::next_prime(size_type n)const {
		auto i = 0;
		for (; i != PRIME_LIST_SIZE; ++i) {
			if (n > prime_list_[i])
				continue;
			else
				break;
		}
		i = (i == PRIME_LIST_SIZE ? PRIME_LIST_SIZE - 1 : i);
		return prime_list_[i];
	}
	template<class Key, class Hash, class KeyEqual, class Allocator>
	Unordered_set<Key, Hash, KeyEqual, Allocator>::Unordered_set(const Unordered_set& ust) {
		buckets_ = ust.buckets_;
		size_ = ust.size_;
		max_load_factor_ = ust.max_load_factor_;
	}
	template<class Key, class Hash, class KeyEqual, class Allocator>
	Unordered_set<Key, Hash, KeyEqual, Allocator>& Unordered_set<Key, Hash, KeyEqual, Allocator>::operator = (const Unordered_set& ust) {
		if (this != &ust) {
			buckets_ = ust.buckets_;
			size_ = ust.size_;
			max_load_factor_ = ust.max_load_factor_;
		}
	}
	//指定对应大小的散列表
	template<class Key, class Hash, class KeyEqual, class Allocator>
	Unordered_set<Key, Hash, KeyEqual, Allocator>::Unordered_set(size_type bucket_count) {
		bucket_count = next_prime(bucket_count);
		buckets_.resize(bucket_count);
		size_ = 0;
		max_load_factor_ = 1.0;
	}
	//将整个容器放入散列表中
	template<class Key, class Hash, class KeyEqual, class Allocator>
	template<class InputIterator>
	Unordered_set<Key, Hash, KeyEqual, Allocator>::Unordered_set(InputIterator first, InputIterator last) {
		size_ = 0;
		max_load_factor_ = 1.0;
		auto len = last - first;
		buckets_.resize(next_prime(len));//获得合适的长度
		for (; first != last; ++first) {
			auto index = bucket_index(*first);
			if (!has_key(*first)) {//不可重复
				buckets_[index].push_front(*first);
				++size_;
			}
		}
	}
	//散列表的首节点需要依个查找
	template<class Key, class Hash, class KeyEqual, class Allocator>
	typename Unordered_set<Key, Hash, KeyEqual, Allocator>::iterator
		Unordered_set<Key, Hash, KeyEqual, Allocator>::begin() {
		size_type index = 0;
		for (; index != buckets_.size(); ++index) {
			if (!(buckets_[index].empty()))
				break;
		}
		if (index == buckets_.size())
			return end();
		return iterator(index, buckets_[index].begin(), this);
	}
	template<class Key, class Hash, class KeyEqual, class Allocator>
	typename Unordered_set<Key, Hash, KeyEqual, Allocator>::iterator
		Unordered_set<Key, Hash, KeyEqual, Allocator>::end() {
		return iterator(buckets_.size() - 1, buckets_[buckets_.size() - 1].end(), this);
	}
	//对某个桶的首尾,直接调用list
	template<class Key, class Hash, class KeyEqual, class Allocator>
	typename Unordered_set<Key, Hash, KeyEqual, Allocator>::local_iterator
		Unordered_set<Key, Hash, KeyEqual, Allocator>::begin(size_type i) {
		return buckets_[i].begin();
	}
	template<class Key, class Hash, class KeyEqual, class Allocator>
	typename Unordered_set<Key, Hash, KeyEqual, Allocator>::local_iterator
		Unordered_set<Key, Hash, KeyEqual, Allocator>::end(size_type i) {
		return buckets_[i].end();
	}
	//到对应桶查找
	template<class Key, class Hash, class KeyEqual, class Allocator>
	typename Unordered_set<Key, Hash, KeyEqual, Allocator>::iterator
		Unordered_set<Key, Hash, KeyEqual, Allocator>::find(const key_type& key) {
		auto index = bucket_index(key);
		for (auto it = begin(index); it != end(index); ++it) {
			if (key_equal()(key, *it))
				return iterator(index, it, this);
		}
		return end();
	}
	//数:不是0就是1
	template<class Key, class Hash, class KeyEqual, class Allocator>
	typename Unordered_set<Key, Hash, KeyEqual, Allocator>::size_type
		Unordered_set<Key, Hash, KeyEqual, Allocator>::count(const key_type& key) {
		auto it = find(key);
		return it == end() ? 0 : 1;
	}
	//插入并且返回pair说明是否存在
	template<class Key, class Hash, class KeyEqual, class Allocator>
	mySTL::pair<typename Unordered_set<Key, Hash, KeyEqual, Allocator>::iterator, bool>
		Unordered_set<Key, Hash, KeyEqual, Allocator>::insert(const value_type& val) {
		if (!has_key(val)) {
			if (load_factor() > max_load_factor())//哈希表退化,需要重新哈希
				rehash(next_prime(size()));
			auto index = bucket_index(val);
			buckets_[index].push_front(val);
			++size_;
			return mySTL::pair<iterator, bool>(iterator(index, buckets_[index].begin(), this), true);
		}
		return mySTL::pair<iterator, bool>(end(), false);
	}
	//批量插入
	template<class Key, class Hash, class KeyEqual, class Allocator>
	template<class InputIterator>
	void Unordered_set<Key, Hash, KeyEqual, Allocator>::insert(InputIterator first, InputIterator last) {
		for (; first != last; ++first) {
			insert(*first);
		}
	}
	//删除与查找类似,调用list实现
	template<class Key, class Hash, class KeyEqual, class Allocator>
	typename Unordered_set<Key, Hash, KeyEqual, Allocator>::size_type
		Unordered_set<Key, Hash, KeyEqual, Allocator>::erase(const key_type& key) {
		auto it = find(key);
		if (it == end()) {
			return 0;
		}
		else {
			erase(it);
			return 1;
		}
	}
	//
	template<class Key, class Hash, class KeyEqual, class Allocator>
	typename Unordered_set<Key, Hash, KeyEqual, Allocator>::iterator
		Unordered_set<Key, Hash, KeyEqual, Allocator>::erase(iterator position) {
		--size_;
		auto t = position++;
		auto index = t.bucket_index_;
		auto it = buckets_[index].erase(t.iterator_);
		return position;
	}
	//设置和返回factor的函数
	template<class Key, class Hash, class KeyEqual, class Allocator>
	float Unordered_set<Key, Hash, KeyEqual, Allocator>::max_load_factor()const {
		return max_load_factor_;
	}
	template<class Key, class Hash, class KeyEqual, class Allocator>
	void Unordered_set<Key, Hash, KeyEqual, Allocator>::max_load_factor(float z) {
		max_load_factor_ = z;
	}
	//重新哈希
	template<class Key, class Hash, class KeyEqual, class Allocator>
	void Unordered_set<Key, Hash, KeyEqual, Allocator>::rehash(size_type n) {
		if (n <= buckets_.size())
			return;
		Unordered_set temp(next_prime(n));
		for (auto& val : *this) {
			temp.insert(val);
		}
		TinySTL::swap(*this, temp);
	}
	template<class Key, class Hash, class KeyEqual, class Allocator>
	void swap(Unordered_set<Key, Hash, KeyEqual, Allocator>& lhs,
		Unordered_set<Key, Hash, KeyEqual, Allocator>& rhs) {
		mySTL::swap(lhs.buckets_, rhs.buckets_);
		mySTL::swap(lhs.size_, rhs.size_);
		mySTL::swap(lhs.max_load_factor_, rhs.max_load_factor_);
	}
}
#endif
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值