#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;
}