经过长时间的学习终于可以开始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