笔记——封装unordered_map&&unordered_set

底层是哈希表,先介绍下什么是哈希表,前面的笔记有写,这里回忆一下

我上个笔记实现的哈希表指的是数组中存链表,而链表中存想要存的数据,而链表是自己实现的,
链表:前一个元素的地址,下一个元素地址,要存的数据(可以是pair<K,V>类型的数据,也可以是K类型的数据,这是要一一个hash表来封装两个容器,也就是说是公用一个hash表)

迭代器

要封装成容器,必不可少的就是迭代器iterator,所以要先实现迭代器

先实现底层hash表的迭代器,再在此基础上封装上层迭代器

先实现迭代器的什么功能

强调功能确定成员变量(在实现类的时候)

首先迭代器类创建出来,而里面的成员根据要实现的功能来确定,也就是说先确定大概的 功能

然后在功能基础上实现成员,大框架有后,剩下的就是填充

里面的成员根据自增(++)来确定,例如在表中的某个桶的某个位置,此时想要迭代到下一个元素,此时要分几种情况

其中一种情况是直接到此桶的下一个元素

另一种情况是此桶没有下个元素,此时就需要找到下个不为空的桶

我们在这里把list叫做 哈希表元素,而迭代器里面的成员包括list里的元素(节点)

而要解决第二种情况,找到下一个不为空,需要哈希表,这样就确定了另一个成员变量,而为了每次在查找下个不为空的桶的时候,需要知道走到空的的位置,也就是说是第几个桶,从第几个桶开始查找,确定查找的起始位置,

这就确定了另一个成员变量,当前桶的位置

这样就哈希表迭代器的成员变量1.节点2.哈希表3.桶的位置
 

迭代器的基本功能

能自增自减(++)(--)(->)(*)(!=)(==)

迭代器成员变量知道后这些功能就简单些

iterator和const_iterator

两种迭代器的区别就是那几个成员函数返回类型包括const,为了减少重复代码,可以把返回类型改成模板类型,

V(数据类型),Ptr(数据的指针类型),Ref(数据的引用),在哈希表中可以迭代器类(迭代器是在哈希表外部实现,在内部进行重命名,相当于在哈希表内部创建 迭代器类),根据模板参数来确定迭代器类型,

封装

以上完成的hash表就已经是unordered_map,而为了兼容unordered_set,需要更改哈希表存的类型,从pair<K,V>类型改成K类型,根据在这两个头文件来决定传的参数类型是pair<K,V>还是K类型,

这两个容器的区别就是存的数据类型不同

再取余数的时候,需要判断是pair类型的还是K类型的,这里就需要仿函数,在封装的头文件传仿函数,

这样模板参数多了一个判断类型的仿函数,

在哈希表内部使用对数据取余数的方式来确定存在哪个桶里,而如果这个数据不是整数,就需要先把数据映射成整数,这就需要另一个仿函数来映射,这样模板参数就又多一个,

总结

迭代器的成员变量需要根据功能来确定

减少代码冗余可以选用模板(例如iterator和const_iterator)

代码部分

#pragma once
#include<iostream>
#include<vector>
#include<string>
using namespace std;

template<class K, class V >
class HashElement;


template<class K,class V,class Ptr,class Ref,class fun >
class _iterator
{
public:
	typedef _iterator<K ,V, Ptr, Ref,fun> Self;
	typedef HashElement<K,V> HashElement;

public:
	HashElement*_node;
	vector<HashElement*>_arr;
	int _bucketposition;
	fun f;

public:
	_iterator()
		:_node(nullptr)
		,_bucketposition(0)
	{}
	
	_iterator( HashElement*node,const int bucketposition,const vector<HashElement*>arr)
	{
		_node = node;
		_arr = arr;
		_bucketposition = bucketposition;
	}
	_iterator(const _iterator& it)
	{
		_node = it._node;
		_arr = it._arr;
		_bucketposition = it._bucketposition;
	}
	Self operator=(const _iterator& it)
	{
		_node = it._node;
		_arr = it._arr;
		_bucketposition = it._bucketposition;
		return *this;
	}
	Self operator++()
	{
		if (_node != nullptr&&_node->_next==nullptr&&_bucketposition<_arr.capacity())
		{
			_bucketposition++;
			if (_bucketposition == _arr.capacity())
			{
				_node = nullptr;
				return *this;
			}
			while (_bucketposition < _arr.capacity())
			{
				if (_arr[_bucketposition] != nullptr)
				{
					_node = _arr[_bucketposition];
					return *this;
				}
				_bucketposition++;
			}
			_node = nullptr;
			return *this;
		}
		if(_node!=nullptr)
		_node = _node->_next;
		return *this;
	}

	Self operator--()
	{
		if (_node != nullptr && _node->_pre == nullptr)
		{
			_bucketposition--;
			
			while (_bucketposition >= 0)
			{
				if (_arr[_bucketposition] != nullptr)
				{
					_node = _arr[_bucketposition];
					return *this;
				}
				_bucketposition--;
			}
			//return _iterator(nullptr);

		}
		_node = _node->_pre;
		return *this;
	}
	Ptr operator->()
	{
		return &f(_node->_data);
	}
	Ref operator*()
	{
		return f(_node->_data);
	}
	bool operator!=(Self it)
	{
		return _node != it._node;
	}


};




template<class K,class V>
class HashElement
{
public:
	typedef HashElement<K,V> HahsElement;
public:
	HashElement() = default;
	K _data;
	HahsElement* _next = nullptr;
	HashElement* _pre = nullptr;
	//State _state = Empty;
	HashElement(K data)
	{
		_data = data;
		_next = nullptr;
		_pre = nullptr;
	}
};


class _relation
{
	int operator()(int data)
	{
		return data;
	}
};


//fun代表数据类型
template<class K,class V,  class fun ,class relation >
class HashTable
{
public:
	typedef HashElement<K,V> HashElement;
	typedef _iterator<K, V,V*,V&,fun> Iterator;
	typedef _iterator<K,  V, const V*, const V&,fun> const_Iterator;


public:
	vector<HashElement*> _arr;
	int _size = 0;


public:
	fun f;
	relation r;
	//迭代器
	Iterator begin()
	{
		int i = 0;
		for (i = 0; i < _arr.size(); i++)
		{
			if(_arr[i]!=nullptr)
				return Iterator(_arr[i],i,_arr);
		}

		return Iterator(nullptr,i,_arr);
	}

	Iterator end()
	{
		return Iterator(nullptr, _arr.capacity(), _arr);
	}

	const_Iterator cbegin()const
	{
		int i = 0;
		for (i = 0; i < _arr.size(); i++)
		{
			if (_arr[i] != nullptr)
				return const_Iterator(_arr[i], i, _arr);
		}

		return const_Iterator(nullptr, i, _arr);
	}

	const_Iterator cend()const
	{
		return const_Iterator(nullptr, _arr.capacity(), _arr);
	}


	

	pair<Iterator,bool> Insert(K data)
	{
		//判断扩容
		if (_size * 10 / _arr.size() >= 7)
		{
			int i = 0;
			vector<HashElement*> newtable;
			newtable.resize(2 * _arr.size());
			for (i = 0; i < _arr.size(); i++)
			{
				HashElement* cur = _arr[i];
				
				while (cur)
				{
					int remainer = r(f(cur->_data)) % newtable.size();
					if (newtable[remainer] == nullptr)
					{
						newtable[remainer] = cur;
						HashElement*next = cur->_next;
						newtable[remainer]->_next = nullptr;
						cur = next;
					}
					else
					{

						HashElement* next = cur->_next;
						cur->_next = newtable[remainer];
						cur->_pre = nullptr;
						newtable[remainer]->_pre = cur;
						newtable[remainer] = cur;
						cur = next;
					}
				}
			}
			
			swap(_arr, newtable);
			int remainer = r(f(data)) % _arr.size();
			if (_arr[remainer] == nullptr)
			{
				_arr[remainer] = new HashElement(data);
			}
			else
			{
				HashElement* newnode = new HashElement(data);
				newnode->_next = _arr[remainer];
				newnode->_pre = nullptr;
				_arr[remainer]->_pre = newnode;
				_arr[remainer] = newnode;
			}
			_size++;
			return make_pair(Iterator(_arr[remainer], remainer, _arr), 1);
		}
		int remainer = r(f(data)) % _arr.size();
		if (_arr[remainer] == nullptr)
		{
			_arr[remainer] = new HashElement(data);
		}
		else
		{
			HashElement* newnode = new HashElement(data);
			newnode->_next = _arr[remainer];
			newnode->_pre = nullptr;
			_arr[remainer]->_pre = newnode;
			_arr[remainer] = newnode;
		}
		_size++;
		return make_pair(Iterator(_arr[remainer],remainer,_arr), 1);
	}

	Iterator Find(K key)
	{
		int remainer = r(f(key)) % _arr.size();
		if (_arr[remainer] != nullptr)
		{
			HashElement* cur = _arr[remainer];
			while (cur)
			{
				if (r(f(cur->_data)) == key)
				{
					return make_pair(Iterator(cur, remainer, _arr), true);
				}
				cur = cur->_next;
			}
			return make_pair(end(), false);
		}
		return make_pair(end(), false);
	}
	HashTable()
	{
		_arr.resize(10);
	}


	bool Erase(K key)
	{
		int remainer = r(f(key)) % _arr.size();
		if (_arr[remainer] != nullptr)
		{
			HashElement* cur = _arr[remainer];
			while (cur)
			{
				if (r(f(cur->_data)) == key)
				{
					if (cur->_pre == nullptr)
					{
						HashElement* next = cur->_next;
						delete cur;
						if(next)
						next->_pre = nullptr;
						_arr[remainer] = next;
						_size--;
						return true;
					}
					else
					{
						HashElement* next = cur->_next;
						HashElement* pre = cur->_pre;
						pre->_next = next;			
						if(next)
						next->_pre = pre;
						_arr[remainer] = next;
						
						delete cur;
						_size--;
						return true;
					}
					
				}
				cur = cur->_next;
			}
			return false;
		}
		return false;
	}

};

#pragma once
#include"Hash.h"

class _SetFun
{
public:
	int& operator()(int data)
	{
		return data;
	}
};

class _Relation
{
public:
	int operator()(int data)
	{
		return data;
	}
};

template<class K,class SetFun=_SetFun,class Relation=_Relation>
class unorderedSet
{
public:
	typedef HashElement<K, K> HahsElement;
	typedef _iterator<K, K, K*, K&, SetFun> iterator;
	typedef _iterator<K, K,const K*,const K&, SetFun> const_iterator;

private:
	HashTable<K, K, SetFun, Relation> unordered_Set;

public:
	pair<iterator, bool> Isert(K data)
	{
		return unordered_Set.Insert(data);
	}
	bool Erase(K data)
	{
		return unordered_Set.Erase(data);
	}
	iterator begin()
	{
		return unordered_Set.begin();
	}
	iterator end()
	{
		return unordered_Set.end();
	}
	const_iterator cbegin()
	{
		return unordered_Set.cbegin();
	}
	const_iterator cend()
	{
		return unordered_Set.cend();
	}

};
#pragma once
#include"Hash.h"
template<class K,class V>
class _MapFun
{
public:
	int &operator()(pair<K,V> data)
	{
		return data.first;
	}
};
class _MapRelation
{
public:
	int operator()(int data)
	{
		return data;
	}
};

template<class K,class V,class MapFun=_MapFun<K,V>,class MapRelation=_MapRelation>
class Unordered_map
{
public:
	typedef  _iterator<pair<K,V>, V, V*, V&,MapFun> iterator;
	typedef  _iterator<pair<K,V>, V,const V*,const V&,MapFun> const_iterator;

private:
	HashTable<pair<K, V>, V, MapFun, MapRelation> unorderedMap;

public:
	pair<iterator, bool> Insert(pair<K,V> data)
	{
		return unorderedMap.Insert(data);
	}
	bool Erase(pair<K,V> key)
	{
		return unorderedMap.Erase(key);
	}
	iterator begin()
	{
		return unorderedMap.begin();
	}
	iterator end()
	{
		return unorderedMap.end();
	}
	const_iterator cbegin()
	{
		return unorderedMap.cbegin();
	}
	const_iterator cend()
	{
		return unorderedMap.cend();
	}
};

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
unordered_set和unordered_mapC++标准库中的容器,用于存储和管理不重复的元素集合和键值对集合。 unordered_set是一个无序的集合容器,其中的元素是唯一的且无序的。它基于哈希表实现,因此插入、删除和查找操作的平均时间复杂度为常数时间O(1)。使用unordered_set可以快速判断一个元素是否存在于集合中。 unordered_map是一个无序的键值对容器,其中的键是唯一的且无序的。它也基于哈希表实现,因此插入、删除和查找操作的平均时间复杂度为常数时间O(1)。使用unordered_map可以根据键快速查找对应的值。 使用unordered_set和unordered_map时,需要包含头文件<unordered_set>和<unordered_map>。以下是它们的基本用法: 1. 创建容器: unordered_set<int> mySet; // 创建一个空的unordered_set unordered_map<string, int> myMap; // 创建一个空的unordered_map 2. 插入元素或键值对: mySet.insert(10); // 插入元素10到unordered_set中 myMap["apple"] = 5; // 插入键值对("apple", 5)到unordered_map中 3. 删除元素或键值对: mySet.erase(10); // 从unordered_set中删除元素10 myMap.erase("apple"); // 从unordered_map中删除键为"apple"的键值对 4. 查找元素或键值对: auto it = mySet.find(10); // 在unordered_set中查找元素10,返回迭代器 if (it != mySet.end()) { // 找到了元素 } auto it = myMap.find("apple"); // 在unordered_map中查找键为"apple"的键值对,返回迭代器 if (it != myMap.end()) { // 找到了键值对 int value = it->second; // 获取对应的值 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

earthwormer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值