自己实现一个映射表(依赖于hash表的链地址法)||c++

开门见山,映射表即存放键值对的一种结构。如果我们要在映射表里面存储一个数字3,这个3可以当作是一个键值,如果我们发现在映射表里面3已经存在,那么我们就把它的值加1。如果没有那么它的值为0,然后根据规则插入到映射表。在C++中的map中,键值对是按照pair的形式进行存储的。

接下来我们用链地址法的hash表的来实现这一结构,不了解链地址的hash表的实现可以参考我的另一篇博客链地址法实现hash表

1.映射表的结构

//储存结点类型
	class Node 
	{
	public:
		Node(KeyType key = KeyType()) :_key(key), _value(ValueType()) {}
		bool operator==(const Node& node)const
		{
			return _key == node._key;
		}
		KeyType _key;
		ValueType _value;
	};
	int _nodeSize;//存储结点的个数
	int _chainSize;//存储链的个数
	vector<list<Node>>_hashMap;//映射表
	double _loadFactor;//负载均衡因子
	HashType _hashValue;//用于计算哈希值

上面是映射表的成员变量,用Node结构来模拟键值对,用链地址法的hash表_hashMap来模拟映射表的。

2.映射表的插入操作

在进行键的插入操作的时候,先要判断键是否存在,如果存在,把相应的值加1完成操作。不存在,要先根据负载均衡因子来判断映射表是否要进行扩容,如果需要扩容,扩容之后由于_chainSize的改变,要将以前已经存储的元素重新进行存储。然后再将当前键存入到映射表中。

void Insert(KeyType key)
	{
		//先判断结点是否存在
		int index = _hashValue(key) % _chainSize;
		for (Node &ele : _hashMap[index])
		{
			//存在,_value+1,
			if (ele._key == key)
			{
				ele._value++;
				cout << "插入成功 value+1" << endl;
				++_nodeSize;
				return;
			}
		}
		//不存在,根据情况对对映射表进行扩容
		int len = GetLen();
		if (_hashMap[index].empty())
			++len;
		//对映射表进行扩容
		if ((double)len / _chainSize >= _loadFactor)
		{
			vector<Node> nodeArr;
			//记录以前的元素,需要进行重新存储
			for (list<Node> l : _hashMap)
			{
				for (Node node : l)
				{
					nodeArr.push_back(node);
				}
				//链表清空
				l.clear();
			}
			//映射表扩容
			_hashMap.resize(2 * _chainSize);
			_loadFactor /= 2.0;
			_chainSize *= 2;

			//重存以前的元素
			for (Node node : nodeArr)
			{
				int location = _hashValue(node._key) % _chainSize;
				_hashMap[location].push_back(node);
			}
		}
		index = _hashValue(key)%_chainSize;
		_hashMap[index].push_back(Node(key));
		++_nodeSize;
		cout << "插入成功" << endl;
	}

3.删除操作

删除操作,需要先判断键对应的值是否为1,为1的话移除此键,不为1将值减1完成操作。

//删除操作
	void Remove(KeyType key)
	{
		int index = _hashValue(key) % _chainSize;
		for (Node &node : _hashMap[index])
		{
			if (node._key == key)
			{
				if (node._value !=ValueType())
				{
					node._value--;
				}
				else
					_hashMap[index].remove(node);
			}
		}
		cout << "删除成功" << endl;
	}

4.源码

# include<iostream>
using namespace std;
# include<vector>
# include<list>
//函数对象,映射函数默认用除留余数法,在这里只返回key值
template<typename KeyType>
class CHash
{
public:
	KeyType operator() (const KeyType& key )
	{
		return key;
	}
};


template<typename KeyType,typename ValueType,typename HashType = CHash<KeyType>>
class HashMap
{
public:
	HashMap(int chainSize=3, double loadFactor = 0.75)
		:_nodeSize(0), _chainSize(chainSize), _loadFactor(loadFactor)
	{
		_hashMap.resize(_chainSize);
	}

	void Insert(KeyType key)
	{
		//先判断结点是否存在
		int index = _hashValue(key) % _chainSize;
		for (Node &ele : _hashMap[index])
		{
			//存在,_value+1,
			if (ele._key == key)
			{
				ele._value++;
				cout << "插入成功 value+1" << endl;
				++_nodeSize;
				return;
			}
		}
		//不存在,根据情况对对映射表进行扩容
		int len = GetLen();
		if (_hashMap[index].empty())
			++len;
		//对映射表进行扩容
		if ((double)len / _chainSize >= _loadFactor)
		{
			vector<Node> nodeArr;
			//记录以前的元素,需要进行重新存储
			for (list<Node> l : _hashMap)
			{
				for (Node node : l)
				{
					nodeArr.push_back(node);
				}
				//链表清空
				l.clear();
			}
			//映射表扩容
			_hashMap.resize(2 * _chainSize);
			_loadFactor /= 2.0;
			_chainSize *= 2;

			//重存以前的元素
			for (Node node : nodeArr)
			{
				int location = _hashValue(node._key) % _chainSize;
				_hashMap[location].push_back(node);
			}
		}
		index = _hashValue(key)%_chainSize;
		_hashMap[index].push_back(Node(key));
		++_nodeSize;
		cout << "插入成功" << endl;
	}
	//得到桶大小
	int GetBucketSize()
	{
		return _chainSize;
	}
	//得到元素个数
	int GetNodeSIze()
	{
		return _nodeSize;
	}
	//删除操作
	void Remove(KeyType key)
	{
		int index = _hashValue(key) % _chainSize;
		for (Node &node : _hashMap[index])
		{
			if (node._key == key)
			{
				if (node._value !=ValueType())
				{
					node._value--;
				}
				else
					_hashMap[index].remove(node);
			}
		}
		cout << "删除成功" << endl;
	}
	//查询操作
	void Query(const ValueType& key)
	{
		int index = _hashValue(key) % _chainSize;
		for (Node node : _hashMap[index])
		{
			if (node._key == key)
			{
				cout << "查询成功" << node._key << ":" << node._value+1 << endl;
				return;
			}
		}
		cout << "查无此元素" << endl;
	}
private:
	int GetLen()
	{
		int len = 0;
		for (list<Node> l: _hashMap)
		{
			if (!l.empty())
			{
				++len;
			}
		}
		return len;;
	}
private:
	//储存结点类型
	class Node 
	{
	public:
		Node(KeyType key = KeyType()) :_key(key), _value(ValueType()) {}
		bool operator==(const Node& node)const
		{
			return _key == node._key;
		}
		KeyType _key;
		ValueType _value;
	};
	int _nodeSize;//存储结点的个数
	int _chainSize;//存储链的个数
	vector<list<Node>>_hashMap;//映射表
	double _loadFactor;//负载均衡因子
	HashType _hashValue;//用于计算哈希值
};
int main()
{
	HashMap<int, int> map(3);
	//测试_loadFactor
	cout << map.GetBucketSize() << endl;
	map.Insert(1);
	map.Insert(2);
	map.Insert(3);
	cout << map.GetBucketSize() << endl;
	//测试插入
	map.Insert(3);
	map.Query(3);
	//删除操作
	map.Remove(3);
	map.Query(3);
	return 0;
}

测试结果如下:

发布了124 篇原创文章 · 获赞 24 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_42214953/article/details/105174509
今日推荐