关于C++中哈希的应用与实现

 1、map  unordered_map   unordered_set

        map<int, int> map; // 可以按照Key 的大小排序,并且 是可以重复的key    ----底层是红黑树    O(logN)
       unordered_map <int, int> um;  //不能有重复的key 并未是没有排序的  但是查找的时间可以达到O(1)的时间复杂度,因为底层是一个哈希桶

#include <iostream>
#include <map>
#include <unordered_map>
#include <unordered_set>
using namespace std;
int main() 
{
	map<int, int> map; // 可以按照Key 的大小排序,并且 是可以重复的key    ----底层是红黑树    O(logN)
	map.insert(make_pair(1,2));
	map.insert(make_pair(6, 20));
	map.insert(make_pair(7, 16));
	map.insert(make_pair(5, 20));
	map.insert(make_pair(2, 7));
	map.insert(make_pair(7, 1));
	for (auto e : map)
		cout << " map :" << e.first << "  , " << e.second << endl;


	//  map  set   multi_map   multi_set   都是中序遍历  ,     O(logN)

	unordered_map <int, int> um;  //不能有重复的key 并未是没有排序的  但是查找的时间可以达到O(1)的时间复杂度,因为底层是一个哈希桶

	um.insert(make_pair(1, 2));
	um.insert(make_pair(6, 20));
	um.insert(make_pair(7, 16));
	um.insert(make_pair(5, 20));
	um.insert(make_pair(2, 7));
	um.insert(make_pair(7, 1));
	um.insert(make_pair(2, 17));
	um.insert(make_pair(2, 57));
	um.insert(make_pair(2, 77));
	for (auto e : um)
		cout << "unordered_map : " << e.first << "  , " << e.second << endl;





	unordered_set <int>  us;
	us.insert(10);
	us.insert(50);

	unordered_set <int>::iterator it = us.begin();
	while (it != us.end())
	{
		cout << "++++unordered_set+++++++  " <<*it <<endl;
		++it;
	}

	return 0;
}

二、哈希函数

例如:数据集合{1,7,6,4,5,9};
哈希函数设置为:hash(key) = key % capacity; capacity为存储元素底层空间大小,这里设置为10

哈希冲突:

若上面再来一个数据44,那么依据上面的计算就是错误的,4 的那个位置有两个值,这种情况就是hash 冲突。不同关键字通过相同哈希哈数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。哈希冲突的解决可以分为两大类,闭散列和开散列

闭散列:开发地址法

当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把key存放到冲突位置中的“下一个” 空位置中去。那如何寻找下一个空位置呢?

线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。

 那么这种情况下就可能发生两种操作,第一便是查找,第二便是删除:

查找的话就是1 通过hash 函数计算的方法计算出是在那个索引下面,

                      2 判断这个索引的值和要查找的是不是一样,如果不一样就依次向后面找

2 二次探测 Hi=(H0+i^2)%m   m 是表的大小,H0是第一次计算得到的哈希值,  i= 123....

三、开放地址法解决哈希冲突

#include <iostream>
#include <map>
#include <unordered_map>
#include <vector>
#include<string.h>
using namespace std;


enum Status  // 表示hash 表的状态
{
	EMPTY,
	EXIST,
	DELETE
};

template<class K,class V >
struct DataNode
{
public :
	pair<K, V> _kv = pair<K, V>();
	Status status= EMPTY;
};


template<class K, class V >
class MyHashTable
{
public:
	typedef struct DataNode<K, V> HashNode;
	MyHashTable(size_t  n = 5) :h_size(0)
	{
		hv_Node.resize(n);
	}

	void  CheckCapacity()
	{
		if (hv_Node.size() == 0|| h_size*10/ hv_Node.size()>=7) 
		{
			// 开始扩容
			h_size = hv_Node.size() == 0 ? 5 : 2 * hv_Node.size();
			MyHashTable<K,V> newV_Node(h_size);
			//将扩容之前的数据全都复制到这个新的容器里面
			for (int i = 0; i < hv_Node.size(); i++) {
				if (hv_Node[i].status == EXIST)
				{
					newV_Node.insert(hv_Node[i]._kv);
				}
			
			}

			swap(hv_Node, newV_Node.hv_Node);
		}


	}

	// 插入数据
	bool insert(const pair<K,V> &kv) 
	{
		// 检测容量
		CheckCapacity();
		// 利用哈希函数进行位置的计算,这里用的就是除留余数发
		int  index = kv.first % hv_Node.size();

		while (hv_Node[index].status==EXIST) // 如果index 这个位置已经有值了
		{
			// 主要是看index的位置是不是和要即将插入的K相同
			if (hv_Node[index].status==EXIST&& hv_Node[index]._kv.first==kv.first) {
				return  false;
				++index;
				if (index == hv_Node.size())
				{
					index = 0;
				}
			}
		}
		// 进过上面的循环没有找到形同的K
		hv_Node[index]._kv = kv;
		hv_Node[index].status = EXIST;
		++h_size;
		return  true;

	}


	HashNode* FindByK(const K &key)
	{
		//先利用哈希函数进行位置计算出key的位置
		int  index = key % hv_Node.size();

		while (hv_Node[index].status != EMPTY) // 如果index 这个位置已经有值了
		{
			// 主要是看index的位置是不是和要即将插入的K相同
			if (hv_Node[index].status == EXIST && hv_Node[index]._kv.first == key)
			{
				return  &hv_Node[index];
				++index;
				if (index == hv_Node.size())
				{
					index = 0;
				}
			}
		}
		return NULL;
	}

	bool erase(const K& key)
	{
		HashNode* cur = find(key);
		if (cur)
		{
			//删除 只修改状态 
			cur->status = DELETE;
			--h_size;
			return true;
		}
		return false;
	}

	HashNode*  operator [](const K& key)
	{
		return FindByK(key);
	}
	vector<HashNode> hv_Node;  //数据容器
	size_t   h_size;  // 表的大小

};
#if 1



int  main() 
{
	MyHashTable<int,string> hashmap =  MyHashTable<int, string>();
	pair<int, string> p1,p2,p3,p4,p5,p6;
	p1.first = 1;
	p1.second = "aaaa";
	p2.first = 2;
	p2.second = "bbbb";
	p3.first = 3;
	p3.second = "ccc";
	p4.first = 4;
	p4.second = "dd";
	p5.first = 5;
	p5.second = "eee";
	p6.first = 6;
	p6.second = "fff";
	hashmap.insert(p1);
	hashmap.insert(p2);
	hashmap.insert(p3);
	hashmap.insert(p4);
	hashmap.insert(p5);
	hashmap.insert(p6);
	//hashmap[2];
	//const pair<K,V> &kv
	//for(auto e: hashmap)
	cout << "MyHashTable [] : " << hashmap[2]->_kv.first << ",   " << hashmap[2]->_kv.second << endl;
	cout << "MyHashTable : "<< hashmap.FindByK(3)->_kv.second << ",   " << hashmap.FindByK(6)->_kv.second << endl;
	return 0;
}
#endif // 0

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值