给子定义类定义hash计算,是的可以使用标准库的散列容器 unordered_set 和 unordered_map,有多重方法实现:1)给标准库中的 hash / equal_to实例化一个自定义类的类型;2)自定义函数对象
公共部分,自定义类,自定义数据和测试函数
// 自定义销售类
class Sales_data {
friend class std::hash<Sales_data>; // 友元,便于访问数据进行hash计算
friend class std::equal_to<Sales_data>; // 友元,便于访问数据进行相等判断
public:
Sales_data() = default; // 默认构造函数
Sales_data(const string bn) : bookNo(bn), units_sold(0), revenue(0) {}
Sales_data(const string bn, unsigned us, double re) : bookNo(bn), units_sold(us), revenue(re) {}
//private:
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
// 测试数据
vector<Sales_data> salesData{Sales_data("book1"), Sales_data{"book2"},
Sales_data("book3"), Sales_data("book4")};
vector<std::pair<Sales_data, int>> salesDataPari{{Sales_data("book1"), 1},
{Sales_data{"book2"}, 2},
{Sales_data("book3"), 3},
{Sales_data("book4"), 4}};
// 测试函数
template<typename S, typename M>
void compareTest(const S &sduset, const M &sdumap) {
// S unordered_set<Sales_data>
// M unordered_map<Sales_data, int>
assert(sduset.find(Sales_data("book1")) != sduset.end());
assert(sduset.find(Sales_data("book3")) != sduset.end());
assert(sduset.find(Sales_data("book5")) == sduset.end());
assert(sdumap.count(Sales_data("book1")) == 1);
assert(sdumap.count(Sales_data("book4")) == 1);
assert(sdumap.count(Sales_data("book5")) == 0);
assert(sdumap.find(Sales_data("book1")) != sdumap.end());
assert(sdumap.find(Sales_data("book4")) != sdumap.end());
assert(sdumap.find(Sales_data("book5")) == sdumap.end());
assert(sdumap.find(Sales_data("book1"))->second == 1);
assert(sdumap.find(Sales_data("book4"))->second != 5);
}
1、给标准库中的 hash / equal_to实例化一个自定义类的类型
// 打开std命名空间,以便特例化std::hash / std::equal_to
namespace std {
// 散列, hash值计算
template<>
struct hash<Sales_data> {
using result_type = std::size_t;
using argument_type = Sales_data;
std::size_t operator()(const Sales_data &rhs) const {
return std::hash<string>()(rhs.bookNo) ^
std::hash<unsigned>()(rhs.units_sold) ^
std::hash<double>()(rhs.revenue);
}
};
// 比较相等
template<>
struct equal_to<Sales_data> {
typedef Sales_data first_argument_type;
typedef Sales_data second_argument_type;
typedef bool result_type;
bool operator()(const Sales_data &lhs, const Sales_data &rhs) const {
return lhs.bookNo == rhs.bookNo &&
lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue;
}
};
} // 关std闭命名空间, 注意,没有;
使用和测试
void HashWithStd() {
unordered_set<Sales_data> sduset(salesData.cbegin(), salesData.cend()); // 用salesData初始化set
unordered_map<Sales_data, int> sdumap(salesDataPari.cbegin(), salesDataPari.cend()); // 用salesDataPari初始化map
compareTest(sduset, sdumap); // 测试数据插入是否正常
return;
}
2、函数对象实现
// 用函数对象实现hash
class SalesDataHash {
public:
std::size_t operator()(const Sales_data &rhs) const {
return std::hash<string>()(rhs.bookNo) ^
std::hash<unsigned>()(rhs.units_sold) ^
std::hash<double>()(rhs.revenue);
}
};
class SalesDataEqual {
public:
bool operator()(const Sales_data &lhs, const Sales_data &rhs) const {
return lhs.bookNo == rhs.bookNo &&
lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue;
}
};
使用和测试
void HashWithFunctionObj() {
unordered_set<Sales_data, SalesDataHash, SalesDataEqual> sduset(salesData.cbegin(), salesData.cend());
unordered_map<Sales_data, int, SalesDataHash, SalesDataEqual> sdumap(salesDataPari.cbegin(),
salesDataPari.cend());
compareTest(sduset, sdumap);
return;
}