用哈希封装unordered_map和unordered_set

1.底层哈希(链地址)

template<class T>
struct HashNode
{
	HashNode<T> _next;
	T _data;
	HashNode(const T& data = T())
		:_next(nullptr)
		, _data(data)
	{}
};

2.成员变量

template<class K, class T, class KeyOfT, class HF>
class HashTable;
template<class K,class T, class Ref,class Ptr,class KeyOfT, class HF>
struct HashIterator
{
	typedef HashNode<T> Node;
	typedef HashIterator<K, T, Ref, Ptr, KeyOfT, HF> self;
	typedef HashIterator<K, T, T&, T*, KeyOfT, HF> iterator;
	typedef HashTable<K, T, KeyOfT, HF> HT;
	Node* _node;
	HT* _ht;//走到头之后要找的下一个节点
};

3.简单函数

HashIterator(Node*&node=nullptr,Node*&ht=nullptr)
	:_node(node)
	,_ht(ht)
{}
HashIterator(const iterator&it)
	:_node(it._node)
	, _ht(it._ht)
{}
Ref& operator*()const
{
	return _node->_data;
}
Ptr& operator->()const
{
	return &(_node->_data);
}
bool operator==(const self&se)
{
	return _node == se._node;
}
bool operator!=(const self& se)
{
	return _node != se._node;
}

左右++

1.下一个节点为空则下一位

2.为空则取模算出哈希地址,再线性探测

self& operator++()
{
	Node* node = _node;
	if (node->_next)
	{
		_node = node->_next;
		return *this;
	}
	else
	{
		KeyOfT kot;
		size_t hash = HF(kot(_node->_data)) % _ht->_tables.size()+1;
		for (hash; hash < _ht->_tables.size(); hash++)
		{
			if (_ht->tables[hash])
			{
				_node = _ht->tables[hash];
				return *this;
			}
 
		}
		_node = nullptr;
		return *this;
	}
}
self operator++(int)
{
	self new_self=*this;
	(*this)++;
	return new_self;
}

后置++就是调用前置++

哈希表

template<class K, class T, class KeyOfT, class HF>
class HashTable
{
	template<class K, class T, class Ref, class Ptr, class KeyOfT, class HF>
	friend struct HashIterator;
	typedef HashNode<T> Node;
public:
protected:
	vector<Node*> _tables;
	size_t _size = 0;//有效数据个数
};

迭代器要返回私有成员,所以要声明友元

KEYOFT是分别封装map和set类型

模板参数HF即是HashFunc,哈希函数,用于辅助键值转化为整型进行取模操作

构造和析构

HashTable(size_t size = 10)
{
	_tables.resize(size);
}
~HashTable()
{
	for (auto hash_node : _tables)
	{
		while (hash_node)
		{
			Node* new_node = hash_node->_next;
			delete hash_node;
			hash_node = new_node;
		}
	}
}

begin和end

begin返回最开始不为空的哈希桶的迭代器,而不是最开始的哈希桶的迭代器

end返回空迭代器

构造迭代器需要传入哈希表本身的地址,这里直接传this指针即可

typedef HashIterator< K,T, T&, T*,  KeyOfT,  HF> iterator;
typedef HashIterator< K, T, const T&, const T*,  KeyOfT,  HF> const_iterator;
iterator begin()
{
	for (size_t i = 0; i < _tables.size(); i++)
		if (_tables[i])
			return iterator(_tables[i], this);
	return iterator(nullptr, this);
}
const_iterator begin()const
{
	for (size_t i = 0; i < _tables.size(); i++)
		if (_tables[i])
			return const_iterator(_tables[i], this);
	return const_iterator(nullptr, this);
}
iterator end()
{
	return iterator(nullptr, this);
}
const_iterator end()
{
	return const_iterator(nullptr, this);
}

find

返回类型是迭代器,运用一个仿函数来寻找

iterator Find(const K&key)
{
	HF hf;
	KeyOfT kot;
	size_t hash = hf(key) % _tables.size();
	Node* cur = _tables[hash];
	while (cur)
	{
		if (kot(cur->_data) == key)
			return iterator(cur,_tables);
		cur = cur->_next;
	}
	return iterator(nullptr,_tables);
}

insert

如果空间不够就扩容,返回类型为pair,第一个是迭代器,第二个是bool

	pair<iterator,bool> Insert(T& data)
{
	KeyOfT kot;
	HF hf;
	iterator it = Find(kot(data));
	if (it._node)
	{
		return make_pair(it, false);
	}
	if (_size == _tables.size())
	{
		vector<Node*> new_tables(_size * 2);
		for (auto node : _tables)
		{
			while (node)
			{
				Node* next = node->_next;
				size_t hash = hf(kot(node->_data)) % new_tables.size();
				node->_next = new_tables[hash];
				new_tables[hash] = node;
				node = next;
			}
		}
		_tables.swap(new_tables);
	}
	
	size_t hash = hf(kot(data)) % _tables.size();
	Node* cur = _tables[hash];
	Node* p(data);
	p->_next = cur;
	_tables[hash] = p;
	_size++;
	return make_pair(iterator(p,this),true);
}

erase

	bool Erase(const K& key)
{
	HF hf;
	KeyOfT kot;
	size_t hash = hf(key) % _tables.size();
	Node* cur = _tables[hash];
	Node* pre = nullptr;
	while (cur)
	{
		if (kot(cur->data) == key)
			break;
		pre = cur;
		cur = cur->_next;
	}
	if (cur == nullptr)
		return false;
	_size--;
	if (pre == nullptr)
		_tables[hash] = cur->_next;
	else
		pre->_next = cur->_next;
	delete cur;
	return true;
}

unorered_set

成员变量和仿函数

template<class K,class HF=HashFunc<K>>
class unordered_set
{
public:
	struct SetKeyOfT
	{
		K& operator()(const K& key)
		{
			return key;
		}
	};
protected:
	HashTable<K, K, SetKeyOfT, HF> _hf;
};

1.SETKEYOFT直接返回T

2.哈希函数可以自己写

begin和end

typedef typename HashTable<K, K, SetKeyOfT, HF>::iterator iterator;
typedef typename HashTable<K, K, SetKeyOfT, HF>::const_iterator const_iterator;
iterator begin()
{
	return _ht.begin();
}
const_iterator begin()const
{
	return _ht.begin();
}
iterator end()
{
	return _ht.end();
}
const_iterator end()const
{
	return _ht.end();
}

在c++中,iterator默认为变量名,如果要作为类型名则需要在前面加上typename加上typename关键字

由于key不能修改,所以普通和const迭代器均为const迭代器

我们称set的begin为A,哈希的begin为B,A的实现是对B的调用,在A的参数是普通迭代器时,B也是普通迭代器,B的返回值也是普通迭代器,但A的返回值是const迭代器,所以这里需要用普通迭代器创建一个const迭代器的临时变量,这就用到之前写的拷贝构造函数了

find

也有普通向const的转换

iterator Find(const K&key)
{
	return _ht.Find(key);
}

insert

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

erase

bool Erase(const K& key)
{
	return _ht.Erase(key);
}

unordered_map

成员变量和仿函数

template<class K,class V,class HF=HashFunc<K>>
class unordered_map
{
	struct MapKeyOfT
{
	const K& operator()(const pair<K, V>&kv)
	{
		return kv.first;
	}
	};
protected:
	HashTable<K, pair<const K, V>, MapKeyOfT, HF> _ht;
};

begin和end

typedef typename HashTable<K, pair<K,V>, MapKeyOfT, HF>::iterator iterator;
typedef typename HashTable<K, pair<K,V>, MapKeyOfT, HF>::const_iterator const_iterator;
iterator begin()
{
	return _ht.begin();
}
const_iterator begin()const
{
	return _ht.begin();
}
iterator end()
{
	return _ht.end();
}
const_iterator end()const
{
	return _ht.end();
}

1.加上typename关键字,编译器才能识别类型

2.unordered_map不允许修改key,故普通迭代器和const的pair中的K都要加上const修饰,但是允许修改存储的data,所以普通和const迭代器一一对应

find

iterator Find(const K& key)
{
	return _ht.Find(key);
}

insert

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

operator[]

V& operator[](const& K key)
{
	return (*(_ht.Insert(make_pair(key, V()))).first).second;
}
//或者你也可以这么写
V& operator[](const K& key)
{
	pair<iterator, bool> cur = insert(make_pair(key, V()));
	return cur.first->second;
}

返回值是value的引用,我们可以直接进行修改 

erase

bool Erase(const K& key)
{
	return _ht.Erase(key);
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值