哈希表

链地址法实现的哈希表结构(一)

  • 该链表中存放的是键值对
#include<iostream>
#include<vector>
#include<list>
using namespace std;
template<typename T>
class CHash
{
public:
	int operator()(const T &val)
	{
		return val;//默认用除留余数法
	}
}; // string  User  People

template<>
class CHash<string>//特例化
{
public:
	int operator()(const string &val)
	{
	
		int sum = 0;
		for (int i = 0; i < val.length(); ++i)
		{
			sum += (val[i] >> i);
		}
		return sum;
	}
};
// key 链地址法实现的哈希表结构 【key,id value Person】 
template<typename K, typename V>
struct MyPair
{
	MyPair(K k = K(), V v = V())
		:first(k), second(v) {}
	K first; // key
	V second; // value
};
template<typename K, typename V>
bool operator==(const MyPair<K, V> &lhs, const MyPair<K, V> &rhs)
{
	return lhs.first == rhs.first;
}

template<typename K, typename V>
MyPair<K, V> mymake_pair(const K &key, const V &val)
{
	return MyPair<K, V>(key, val);
}

template<typename K, typename V, typename HashType = CHash<K>>
class CHashMap // 映射表  key -> value
{
public:
	CHashMap(int size = 3, double lf = 0.75)
		:_loadFactor(lf), _usedBuckets(0)
	{
		// 给哈希表开辟数组空间的
		_hashVec.resize(size);
	}
	void put(const MyPair<K, V> &pair)
	{
		double lf = _usedBuckets * 1.0 / _hashVec.size();
		cout << "size:" << _hashVec.size() << " loadfactor:" << lf << endl;
		if (lf >= _loadFactor)
		{
			resize();
		}
		int index = _hash(pair.first) % _hashVec.size();
		list<MyPair<K,V>> &curList = _hashVec[index];
		if (curList.empty())
		{
			curList.push_front(pair);
			_usedBuckets++;
		}
		else
		{
			auto it = find(curList.begin(), curList.end(), pair);
			if (it == curList.end())
			{
				curList.push_front(pair);
			}
		}
	}
	// 删除哈希表中的元素
	void remove(const K &key)
	{
		int index = _hash(key) % _hashVec.size();
		list<MyPair<K, V>> &curList = _hashVec[index];
		if (!curList.empty())
		{
			// 1.在list怎么找val
			auto it = find(curList.begin(), curList.end(), MyPair<K,V>(key));
			// 2.找到val,删除,找不到,return
			if (it != curList.end())
			{
				curList.erase(it);
				// 3.删除val,如果桶变成空的,要给
				if (curList.empty())
				{
					_usedBuckets--;
				}
			}
		}
	}
	// 在哈希表中查找元素   table.query(10);    table[10]
	// map["3452346"] 1.查询功能 2.赋值功能 map["3452346"]="zhangsan" 3.增加
	V& operator[](const K &key)  // MyPair<K,V>
	{
		int index = _hash(key) % _hashVec.size();
		list<MyPair<K, V>> &curList = _hashVec[index];
		if (!curList.empty())
		{
			// 1.在list怎么找val
			auto it = find(curList.begin(), curList.end(), MyPair<K, V>(key));
			// 2.找到val,删除,找不到,return
			if (it != curList.end())
			{
				return it->second;
			}
		}
		// 没有找到
		curList.push_front(MyPair<K,V>(key));
		//return curList.insert(curList.begin(), MyPair<K, V>(key))->second;
		return curList.begin()->second;
	}
private:
	vector<list<MyPair<K, V>>> _hashVec;
	double _loadFactor; // 记录加载因子
	int _usedBuckets;
	HashType _hash;  // 专门计算T类型对象的哈希值的

	//获取素数
	int getPrime(int n)
	{
		for (int i = n + 1;; ++i)
		{
			int k = sqrt(i);
			int j = 2;
			for (; j <= k; ++j)
			{
				if (i % j == 0)
					break;
			}
			if (j > k)
			{
				return i;
			}
			else
			{
				continue;
			}
		}
	}

	// 动态扩容
	void resize()
	{
		// 1.先把现有的哈希表交换到老的容器当中
		vector<list<MyPair<K, V>>> _oldhash;
		_oldhash.swap(_hashVec);

		// 2.给_hashVec resize桶内存
		_hashVec.resize(getPrime(_oldhash.size()));

		// 3.遍历old哈希表,的每一个链表的节点,计算其散列码,splice到新的hash中
		for (auto it = _oldhash.begin(); // it -> list<int>
			it != _oldhash.end();
			++it)
		{
			if (!it->empty())
			{
				for (auto it1 = it->begin(); it1 != it->end();)
				{
					int index = _hash(it1->first) % _hashVec.size();
					list<MyPair<K, V>> &mylist = _hashVec[index];
					if (!mylist.empty())
					{
						// 4.如果桶被第一次占用,_usedBuckets++
						_usedBuckets++;
					}
					// 把旧的hash表中的list节点直接搬到新的哈希表当中
					mylist.splice(mylist.begin(), *it, it1);
					it1 = it->begin();
				}
			}
		}
	}
};
int main()
{
	CHashMap<int, int> hashMap;
	
	hashMap.put(mymake_pair(10, 20));
	hashMap.put(mymake_pair(14, 45));
	hashMap.put(mymake_pair(18, 73));
	hashMap.put(mymake_pair(19, 89));
	hashMap[20] = 987;

	cout << hashMap[20] << endl;




	return 0;
}

list成员splice函数的用法

语法

  void splice( iterator pos, list &lst; );
  void splice( iterator pos, list &lst;, iterator del );
  void splice( iterator pos, list &lst;, iterator start, iterator end );

解释

  • splice()函数把lst连接到pos的位置。如果指定其他参数,则插入lst中del所指元素到现链表的pos上,或者用start和end指定范围。

链地址法实现的哈希表结构(二)

  • 该哈希表中只存放单个数据
template<typename T>
class CHash
{
public:
	int operator()(const T &val)
	{
		// 默认用除留余数法
		return val;
	}
}; 
template<>
class CHash<string>
{
public:
	int operator()(const string &val)
	{
		// hello  olleh
		int sum = 0;
		for (int i = 0; i < val.length(); ++i)
		{
			sum += (val[i]>>i);
		}
		return sum;
	}
};


// 链地址法实现的哈希表结构 
template<typename T, typename HashType = CHash<T>>
class CHashTable
{
public:
	CHashTable(int size = 3, double lf = 0.75)
		:_loadFactor(lf), _usedBuckets(0)
	{
		// 给哈希表开辟数组空间的
		_hashVec.resize(size);
	}
	void put(const T &val)
	{
		double lf = _usedBuckets * 1.0 / _hashVec.size();
		cout << "size:" << _hashVec.size() << " loadfactor:" << lf << endl;
		if (lf >= _loadFactor)//动态扩容的条件
		{
			resize();
		}
		int index = _hash(val) % _hashVec.size();
		list<int> &curList = _hashVec[index];
		if (curList.empty())
		{
			curList.push_front(val);
			_usedBuckets++;
		}
		else
		{
			auto it = find(curList.begin(), curList.end(), val);
			if (it == curList.end())
			{
				curList.push_front(val);
			}
		}
	}
	// 删除哈希表中的元素
	void remove(const T &val)
	{
		int index = _hash(val) % _hashVec.size();
		list<T> &curList = _hashVec[index];
		if (!curList.empty())
		{
			// 1.在list怎么找val
			auto it = find(curList.begin(), curList.end(), val);
			// 2.找到val,删除,找不到,return
			if (it != curList.end())
			{
				curList.erase(it);
				// 3.删除val,如果桶变成空的,要给
				if (curList.empty())
				{
					_usedBuckets--;
				}
			}
		}
	}
	// 在哈希表中查找元素   table.query(10);    table[10]
	bool operator[](const T &val)
	{
		int index = _hash(val) % _hashVec.size();
		list<T> &curList = _hashVec[index];
		if (!curList.empty())
		{
			// 1.在list怎么找val
			auto it = find(curList.begin(), curList.end(), val);
			// 2.找到val,删除,找不到,return
			if (it != curList.end())
			{
				return true;
			}
		}
		return false;
	}
private:
	vector<list<int>> _hashVec;
	double _loadFactor; // 记录加载因子
	int _usedBuckets;
	HashType _hash;  // 专门计算T类型对象的哈希值的

	//获取素数
	int getPrime(int n)
	{
		for (int i = n + 1;; ++i)
		{
			int k = sqrt(i);
			int j = 2;
			for (; j <= k; ++j)
			{
				if (i % j == 0)
					break;
			}
			if (j > k)
			{
				return i;
			}
			else
			{
				continue;
			}
		}
	}

	// 动态扩容
	void resize()
	{
		// 1.先把现有的哈希表交换到老的容器当中
		vector<list<int>> _oldhash;
		_oldhash.swap(_hashVec);

		// 2.给_hashVec resize桶内存
		_hashVec.resize(getPrime(_oldhash.size()));

		// 3.遍历old哈希表,的每一个链表的节点,计算其散列码,splice到新的hash中
		for (auto it = _oldhash.begin(); // it -> list<int>
			it != _oldhash.end();
			++it)
		{
			if (!it->empty())
			{
				for (auto it1 = it->begin(); it1 != it->end();)
				{
					int index = _hash(*it1) % _hashVec.size();
					list<int> &mylist = _hashVec[index];
					if (!mylist.empty())
					{
						// 4.如果桶被第一次占用,_usedBuckets++
						_usedBuckets++;
					}
					// 把旧的hash表中的list节点直接搬到新的哈希表当中
					mylist.splice(mylist.begin(), *it, it1);
					it1 = it->begin();
				}
			}
		}
	}
};
int main()
{
	CHashTable<int> hash;
	srand(time(NULL));
	for (int i = 0; i < 8; i++)
	{
		hash.put(i);
	}
	return 0;
}


线性探测法实现的哈希结构


template<typename T, typename HashType= CHash<T>>
class CHashTable
{
public:
	CHashTable(int size = 3, double lf = 0.75)
		:_loadFactor(lf), _usedBuckets(0)
	{
		// 给哈希表开辟数组空间的
		_hashVec.resize(size);
	}
	void put(const T &val)
	{
		double lf = _usedBuckets * 1.0 / _hashVec.size();
		cout << "size:"<< _hashVec.size() << " loadfactor:" << lf << endl;
		if (lf >= _loadFactor)
		{
			resize();
		}
		int index = _hash(val) % _hashVec.size();
		for (int i = index;;i = (i + 1) % _hashVec.size())
		{
			// STATE_UNUSE STATE_USE STATE_USED
			if (_hashVec[i]._state != STATE_USE)
			{
				_hashVec[i]._data = val;
				_hashVec[i]._state = STATE_USE;
				_usedBuckets++;
				break;
			}
		}
	}
	// 删除哈希表中的元素
	void remove(const T &val)
	{
		int index = _hash(val) % _hashVec.size();
		int flag = (index - 1 + _hashVec.size()) % _hashVec.size();
		for (int i = index; ;i = (i + 1) % _hashVec.size())
		{
			if (_hashVec[i]._state == STATE_UNUSE)
				return;

			if (_hashVec[i]._state == STATE_USE
				&&_hashVec[i]._data == val)
			{
				_hashVec[i]._state = STATE_USED;
				_usedBuckets--;
				break;
			}

			if (i == flag)
			{
				return;
			}
		}
	}
	// 在哈希表中查找元素
	bool query(const T &val)
	{
		int index = _hash(val) % _hashVec.size();
		int flag = (index - 1 + _hashVec.size()) % _hashVec.size();
		for (int i = index; ;i = (i + 1) % _hashVec.size())
		{
			if (_hashVec[i]._state == STATE_UNUSE)
				return;
			if (_hashVec[i]._state == STATE_USE 
				&& _hashVec[i]._data == val)
			{
				return true;
			}
			if (i == flag)
			{
				return false;
			}
		}
	}
private:
	// STATE_UNUSE   删除 STATE_USED 0
	enum STATE{ STATE_UNUSE, STATE_USE, STATE_USED };
	struct Node
	{
		Node(T data = T())
			:_data(data), _state(STATE_UNUSE)
		{}
		T _data;
		STATE _state;
	};
	vector<Node> _hashVec; 
	double _loadFactor; // 记录加载因子
	int _usedBuckets;
	HashType _hash;  // 专门计算T类型对象的哈希值的
	//static int _prime[] = {3,11,29, }; 枚举素数

	//获取素数
	int getPrime(int n)
	{
		for (int i = n + 1;; ++i)
		{
			int k = sqrt(i);
			int j = 2;
			for (; j <= k; ++j)
			{
				if (i % j == 0)
					break;
			}
			if (j > k)
			{
				return i;
			}
			else
			{
				continue;
			}
		}
	}

	// 动态扩容
	void resize()
	{
		vector<Node> _oldhash;
		_oldhash.swap(_hashVec);
		_usedBuckets = 0;

		int prime = getPrime(_oldhash.size());
		_hashVec.resize(prime);

		//vector<Node> _newhash;
		//_newhash.resize(get_prime(_hashVec.size()));
		for (int i = 0; i < _oldhash.size(); ++i)
		{
			// STATE_UNUSE STATE_USE STATE_USED
			if (_oldhash[i]._state == STATE_USE)
			{
				put(_oldhash[i]._data);
			}
		}
		
	}
};


int main()
{
	CHashTable<int> hash;
	srand(time(NULL));
	for (int i = 0; i < 8; i++)
	{
		//hash.put(rand() % 100 + 1);
		hash.put(i);
	}
	
	hash.put(2);
	hash.display();
	hash.remove(2);
	hash.display();
	hash.put(2);
	hash.display();
	cout << hash.query(3) << endl;
	cout << hash.query(2) << endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值