首页 > 编程知识 正文

sql同时查询出最大值和最小值,哈希函数是什么

时间:2023-05-06 03:22:42 阅读:154784 作者:1289

上面已经描述了四种无序关联容器(散列容器):unordered_map、unordered_multimap、unordered_set和unordered_multiset

请注意,每个无序容器都指定了默认散列函数和equal_to比较规则,但仅适用于存储基本类型数据的无序容器,如int、double、float和string。 这意味着,如果存储在无序容器中的数据类型是自定义结构或类,则不再应用STL标准库提供的hash和equal_to。

C无序容器的自定义散列函数

可以假设无序的容器包含键-值对的数据,而unordered_set和unordered_multiset容器包含键-值相等的键-值对。 每个键/值对都以哈希表结构存储。 在该存储结构中,散列函数的功能可以根据每个键值对中键的值计算散列值(本质上是整数),散列表可以根据该值确定该键值对的具体存储位置。

简单了解散列函数后,通过接收元素并在内部对该元素进行再加工,最终得到并反馈整形值。 请注意,散列函数只是一个名称,其主体不是普通的函数格式,而是函数对象类。 因此,如果要定制散列函数,则必须定制函数对象类。

关于什么样的函数对象类,可以通过阅读《C++函数对象详解》一节来详细了解,但由于不是本节的重点,因此在此省略说明。

例如,假设您有以下人员类:

类人员{

公共:

人员(string name,int age ) :name ) name ),age ) {};

字符串获取名称() const;

输入获取代理() const;

私有:

字符串名称;

int age;

(;

字符串个人: getname () const { )

return this-name;

}

输入人员: get age () const { )

返回this-age;

}

假设您要创建一个可以包含Person类对象的unordered_set容器。 考虑到人员是自定义类型,因此不再应用默认散列函数,必须将散列函数定制为函数对象类。 例如:

class hash_fun {

公共:

int operator () ) ) const Person A ) const {

return A.getAge (;

}

(;

请注意,重载运算符()时,参数为const类型,并且方法也必须用const限定。

可以看到,您使用了hash_fun函数对象类的)运算符重载方法,为Person类对象定制了合适的散列函数。 每次接收Person类的对象时,散列函数都会返回该对象的age成员变量的值。

实际上,默认散列函数的基础也是作为函数对象类实现的。

这样,在创建包含Person类对象的unordered_set容器时,可以将hash_fun作为参数传递给该容器模板类中的Pred参数。

STD : unordered _ set myset;

但是,此时创建的myset容器还不可用。 容器使用默认的std:equal_to比较规则,但该规则不适用于容器。

C无序集装箱自定义比较规则

与散列函数一样,创建任何无序容器时,都必须指定可以比较容器中每个元素是否相等的规则。

有趣的是,缺省情况下用于无序容器的std:equal_to比较规则本质上还是函数对象类,其底层实现如下:

template

class equal_to

{

公共:

bool operator () (const{ T _Left,const T _Right ) const ) )。

return(_left==_right );

}

(;

可以看到,在基本实现过程中,该规则直接用==运算符比较容器中的任意两个元素是否相等。 这意味着,如果容器支持直接使用==运算符比较存储在容器中的元素类型是否相等,则容器可以使用默认的std:equal_to比较规则。 相反,不能使用。

很明显,上面创建的myset容器内部包含Person类对象,不支持直接使用==运算符进行比较。 在这种情况下,可以通过以下两种方式解决此问题:

>在 Person 类中重载 == 运算符,这会使得 std::equal_to 比较规则中使用的 == 运算符变得合法,myset 容器就可以继续使用 std::equal_to 比较规则;

以函数对象类的方式,自定义一个适用于 myset 容器的比较规则。

1) 重载==运算符

如果选用第一种解决方式,需要注意的是,C++ 中只能以成员函数的形式重载 == 运算符。仍以 Python 类为例,在此类的外部添加如下语句:

bool operator==(const Person &A, const Person &B) {

return (A.getAge() == B.getAge());

}

注意,这里在重载 == 运算符时,2 个参数必须用 const 修饰。

可以看到,通过此方式重载的运算符,当 std::equal_to 函数对象类中直接比较 2 个 Person 类对象时,实际上是在比较这 2 个对象的 age 成员变量是否相等。换句话说,此时的 std::equal_to 规则的含义为:只要 2 个 Person对象的 age 成员变量相等,就认为这 2 个 Person 对象是相等的。

重载 == 运算符之后,就能以如下方式创建 myset 容器:

std::unordered_set myset{ {"zhangsan", 40},{"zhangsan", 40},{"lisi", 40},{"lisi", 30} };

注意,虽然这里给 myset 容器初始化了 4 个 Person 对象,但由于比较规则以各个类对象的 age 值为准,myset 容器会认为前 3 个 Person 对象是相等的,因此最终 myset 容器只会存储 {"zhangsan", 40} 和 {"lisi", 30}。

2) 以函数对象类的方式自定义比较规则

除此之外,还可以完全舍弃 std::equal_to,以函数对象类的方式自定义一个比较规则。比如:

class mycmp {

public:

bool operator()(const Person &A, const Person &B) const {

return (A.getName() == B.getName()) && (A.getAge() == B.getAge());

}

};

在 mycmp 规则的基础上,我们可以像如下这样创建 myset 容器:

std::unordered_set myset{ {"zhangsan", 40},{"zhangsan", 40},{"lisi", 40},{"lisi", 30} };

由此创建的 myset 容器,虽然初始化了 4 个 Person 对象,但 myset 容器根据 mycmp 比较规则,可以识别出前 2 个是相等的,因此最终该容器内部存有  {"zhangsan", 40}、{"lisi", 40} 和 {"lisi", 30} 这 3 个 Person 对象。

总结

总的来说,当无序容器中存储的是基本类型(int、double、float、string)数据时,自定义哈希函数和比较规则,都只能以函数对象类的方式实现。

而当无序容器中存储的是用结构体或类自定义类型的数据时,自定义哈希函数的方式仍只有一种,即使用函数对象类的形式;而自定义比较规则的方式有两种,要么也以函数对象类的方式,要么仍使用默认的 std::equal_to 规则,但前提是必须重载 == 运算符。

如下是本节的完整代码,读者可直接拷贝下来,加深对本节知识的理解:

#include

#include

#include

using namespace std;

class Person {

public:

Person(string name, int age) :name(name), age(age) {};

string getName() const;

int getAge() const;

private:

string name;

int age;

};

string Person::getName() const {

return this->name;

}

int Person::getAge() const {

return this->age;

}

//自定义哈希函数

class hash_fun {

public:

int operator()(const Person &A) const {

return A.getAge();

}

};

//重载 == 运算符,myset 可以继续使用默认的 equal_to 规则

bool operator==(const Person &A, const Person &B) {

return (A.getAge() == B.getAge());

}

//完全自定义比较规则,弃用 equal_to

class mycmp {

public:

bool operator()(const Person &A, const Person &B) const {

return (A.getName() == B.getName()) && (A.getAge() == B.getAge());

}

};

int main()

{

//使用自定义的 hash_fun 哈希函数,比较规则仍选择默认的 equal_to,前提是必须重载 == 运算符

std::unordered_set myset1{ {"zhangsan", 40},{"zhangsan", 40},{"lisi", 40},{"lisi", 30} };

//使用自定义的 hash_fun 哈希函数,以及自定义的 mycmp 比较规则

std::unordered_set myset2{ {"zhangsan", 40},{"zhangsan", 40},{"lisi", 40},{"lisi", 30} };

cout << "myset1:" << endl;

for (auto iter = myset1.begin(); iter != myset1.end(); ++iter) {

cout << iter->getName() << " " << iter->getAge() << endl;

}

cout << "myset2:" << endl;

for (auto iter = myset2.begin(); iter != myset2.end(); ++iter) {

cout << iter->getName() << " " << iter->getAge() << endl;

}

return 0;

}

程序执行结果为:

myset1:

zhangsan 40

lisi 30

myset2:

lisi 40

zhangsan 40

lisi 30

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。