STL源码分析——一个万用的Hash Function

在这里插入图片描述
在这里插入图片描述

#include<iostream>
#include<string>
#include<unordered_set>

class Customer
{
public:
	string fname;
	string lname;
	long no;
	Customer(const string _fname, const string _lname, long _no) :fname(_fname), lname(_lname), no(_no) {}//constructor

};
template<typename T, typename...Types>//C++11中最新支持的可变参数模板(variadic template)
inline void my_hash_val(size_t&seed, const T&val, const Types&...args)
{
	my_hash_combine(seed, val);
	my_hash_val(seed, args...);
}

template<typename...Types>//C++11中最新支持的可变参数模板(variadic template)
inline size_t my_hash_val(const Types&...args)
{
	size_t seed = 0;
	my_hash_val(seed, args...);//递归
	return seed;
}
class mycompare {//由于放入unordred_set中的是类类型,所以要自定义==函数,否则会报错
public:
	bool operator()(const Customer& c1, const Customer& c2)const {
		if (c1.no == c2.no)
		{
			if (c1.fname == c2.fname)
				return c1.lname == c2.lname;
			return false;
		}
		return false;

	}
};
template<typename T>
inline void my_hash_combine(size_t&seed, const T&val)
{
	seed ^= std::hash<T>()(val) //调用标准库的hash仿函数模板(找到T对应的特化版本)
		+ 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

template<typename T>
inline void my_hash_val(size_t&seed, const T&val)
{
	my_hash_combine(seed, val);
}
class CustomerHash//自定义functor
{
public:
	size_t operator()(const Customer&c)const
	{
		return my_hash_val(c.fname, c.lname, c.no);

	}
};




int main()
{
	//unordered_set<int,std::hash<int>>myset;
	unordered_set<Customer, CustomerHash, mycompare>myset;
	/*
	template<
	class Key,
	class Hash = std::hash<Key>,
	class KeyEqual = std::equal_to<Key>,
	class Allocator = std::allocator<Key>
	> class unordered_set;
	*/
	myset.insert(Customer("Xiao", "Shen", 1));
	myset.insert(Customer("Xiao", "Li", 2));
	myset.insert(Customer("Xiao", "Wang", 3));
	myset.insert(Customer("Xiao", "Zhao", 4));
	myset.insert(Customer("Xiao", "Wu", 5));
	myset.insert(Customer("Xiao", "Liu", 6));
	myset.insert(Customer("Xiao", "Tang", 7));
	myset.insert(Customer("Xiao", "Lin", 8));
	myset.insert(Customer("Xiao", "He", 9));
	cout << "哈希表的篮子个数" << myset.bucket_count() << endl;//64

													   //经过自定义的hash function编码后各个对象会落在哪个篮子里
	cout << "No1:" << CustomerHash()(Customer("Xiao", "Shen", 1)) % 64 << endl;
	cout << "No2:" << CustomerHash()(Customer("Xiao", "Li", 2)) % 64 << endl;
	cout << "No3:" << CustomerHash()(Customer("Xiao", "Wang", 3)) % 64 << endl;
	cout << "No4:" << CustomerHash()(Customer("Xiao", "Zhao", 4)) % 64 << endl;
	cout << "No5:" << CustomerHash()(Customer("Xiao", "Wu", 5)) % 64 << endl;
	cout << "No6:" << CustomerHash()(Customer("Xiao", "Liu", 6)) % 64 << endl;
	cout << "No7:" << CustomerHash()(Customer("Xiao", "Tang", 7)) % 64 << endl;
	cout << "No8:" << CustomerHash()(Customer("Xiao", "Lin", 8)) % 64 << endl;
	cout << "No9:" << CustomerHash()(Customer("Xiao", "He", 9)) % 64 << endl;
	system("pause");
	return 0;
}

在这里插入图片描述
还做了一个测试,验证程序正确性:

int main()
{
	//unordered_set<int,std::hash<int>>myset;
	unordered_set<Customer, CustomerHash, mycompare>myset;
	/*
	template<
	class Key,
	class Hash = std::hash<Key>,
	class KeyEqual = std::equal_to<Key>,
	class Allocator = std::allocator<Key>
	> class unordered_set;
	*/
	myset.insert(Customer("Xiao", "Shen", 1));
	myset.insert(Customer("Xiao", "Li", 2));
	myset.insert(Customer("Xiao", "Wang", 3));
	myset.insert(Customer("Xiao", "Zhao", 4));
	myset.insert(Customer("Xiao", "Wu", 5));
	myset.insert(Customer("Xiao", "Liu", 6));
	myset.insert(Customer("Xiao", "Tang", 7));
	myset.insert(Customer("Xiao", "Lin", 8));
	myset.insert(Customer("Xiao", "He", 9));
	myset.insert(Customer("Xiao", "He", 10));
	myset.insert(Customer("Xiao", "He", 11));
	auto iter = myset.find(Customer("Xiao", "He", 10));
	if (iter!= myset.end())
		myset.erase(*iter);
	system("pause");
	return 0;
}

这里可以回忆一下之前学的容器hashtable,如下图所示:
在这里插入图片描述

最后,还有一种方法,利用std中的hash模板偏特化实现,下面这张图的例子一看就懂了。
在这里插入图片描述
再看一道题
在这里插入图片描述
unordered_set中的仿函数默认是std::equal_to,它对内置的类型以及std::string都具有很好的支持,但是不支持自定义类型,需要自定义类型提供对==的重载。而set中的仿函数默认是std::less,是为了对key进行排序,需要自定义类型提供对<的重载。

//template < 
//class T,        
//class Compare = less<T>,        
//class Alloc = allocator<T>      
//> class set;
#include<iostream>
#include<string>
#include<set>
using namespace std;
class Point
{
public:
	int x;
	int y;
	Point(int x, int y) :x(x), y(y) {}
	bool operator<(const Point& point) const
	{
		if (x != point.x)
			return (x < point.x);
		else
			return (y < point.y);
	}
};


bool fun(string&s)
{
	set<Point>my_set;
	int cur_x = 0, cur_y = 0;
	my_set.insert(Point(0, 0));
	
	for (char c : s)
	{
		switch (c) {
		case 'N': ++cur_y; break;
		case 'S': --cur_y; break;
		case 'W': --cur_x; break;
		case 'E': ++cur_x; break;
		}

		if (my_set.find(Point(cur_x, cur_y)) != my_set.end())
		{
			return true;
		}
		else
		{
			my_set.insert(Point(cur_x, cur_y));
		}
	}
	return false;
}
int main()
{
	string s;
	cin >> s;

	cout << fun(s) << endl;

	system("pause");
	return 0;
}
//template < 
//class T,        
//class Compare = less<T>,        
//class Alloc = allocator<T>      
//> class set;
#include<iostream>
#include<string>
#include<set>
using namespace std;
class Point
{
public:
	int x;
	int y;
	Point(int x, int y) :x(x), y(y) {}

};
class myCompare
{
public:
	bool operator()(const Point&p1, const Point&p2)const
	{
		if (p1.x != p2.x)
			return (p1.x < p2.x);
		else
			return (p1.y < p2.y);
	}
};

bool fun(string&s)
{
	set<Point, myCompare>my_set;
	int cur_x = 0, cur_y = 0;
	my_set.insert(Point(0, 0));
	for (char c : s)
	{
		if (c == 'N')
		{
			cur_y++;
		}
		else if (c == 'S')
		{
			cur_y--;
		}
		else if (c == 'E')
		{
			cur_x++;
		}
		else if (c == 'W')
		{
			cur_x--;
		}
		if (my_set.find(Point(cur_x, cur_y)) != my_set.end())
		{
			return true;
		}
		else
		{
			my_set.insert(Point(cur_x, cur_y));
		}
	}
	return false;
}
int main()
{
	string s;
	cin >> s;

	cout << fun(s) << endl;

	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值