赞
踩
经典哈希函数的几个特征:
哈希函数的推广
当若干输入经过哈希函数,得到均匀分布的hash_code,给这些hash_code取模m,则取模后的hash_code在0~m-1上也是均匀分布的。
如何产生1000个独立的哈希函数
将哈希函数的返回值分为两份,如返回值为h,其范围为2^64 =16位 ,则将h分为8位的h_1,与8为的h_2。由哈希函数的特点可知,h_1,h_2是相互独立的。因此令h_3=h_1+h_2;h_4=h_1+ 2Xh_2;…,h_1000=h_1+998Xh_2;即可
经典哈希表的建立过程:
若输入为put(A,0),A为键值,0为实值。若要建立大小为17的hash表(可以用一个数组来实现),将A经过哈希函数得到的hash_code取模与17,则结果必为0~16中的某值。将(A,0)放入这个空间(数组)中对应的下标。如下图:
如上图,(A,0)放入10对应的下标中。接下来,我们采用链式存储的结构(采用该结构也有效解决了哈希冲突的问题)。将(B,1),(C,2),… ;放入哈希表中。若取模结果重复,难么判断键值是否重复,若重复,则覆盖原来的数据,若不重复则将数据接到原来数据块的后面。如下图:
接下来,针对上述建立哈希表的过程的c++代码实现,以及实现删除,查找操作进行代码实现。
代码懒得弄了,我上传了。
c++现在已经使用unordered_map来代替hash_map了,因此这里主要研究unordered_map。实际上unordered_map就相当于java中的hash_map。为了阅读方便,我就直接写成hash_map了。
“直接定址”与“解决冲突”是哈希表的两大特点。hash_map中直接地址用hash函数生成,解决冲突,用比较函数解决。由此可见,要使用哈希表, 和用户相关的是:hash函数和比较函数
在声明自己的哈希函数时要注意以下几点:
比较函数的实现
<1> 重载==运算符
<2> 仿函数
键值为基本数据类型的unordered_map使用
在SGI STL中,提供了以下hash函数:
struct hash<char*>
struct hash<const char*>
struct hash<char>
struct hash<unsigned char>
struct hash<signed char>
struct hash<short>
struct hash<unsigned short>
struct hash<int>
struct hash<unsigned int>
struct hash<long>
struct hash<unsigned long>
好在,系统为string也提供了hash函数hash< string >,因此当键值为string时,不用自己写哈希函数,如下,分别为基本数据类型和自定义数据类型使用unordered_map
#include<iostream>
#include<unordered_map>
#include <string>
using namespace std;
void test1(){
unordered_map<string, int> map;
hm["孙"]=0;
hm["李"]=1;
hm["张"]=2;
for (auto h : map)
{
cout << h.first << "->" << h.second << endl;
}
}
void test2(){
unordered_map<int, int> map;
hm[0]=0;
hm[1]=1;
hm[2]=2;
for (auto h : map)
{
cout << h.first << "->" << h.second << endl;
}
}
int main()
{
test1();//键值为string验证
test2();//键值为int验证
}
但是什么时候我们才要进行hash函数与比较函数的重写呢?在键值为自定义数据类型的时候,或者当键值string类型时,需要对其进行一些操作时。
//自定义数据类型作为键值:
struct Node
{
Node(int data, string letter){ this->data = data; this->letter = letter; }
int data;
string letter;
bool operator==(const Node & p) const
{
return data == p.data && letter == p.letter;
}
};
struct hash_name
{
size_t operator()(const Node & p) const{
return hash<string>()(p.letter) ^ hash<int>()(p.data);
}
};
int main(void)
{
Node n1(1, "a");
Node n2(2, "b");
Node n3(3, "c");
Node n4(4, "d");
unordered_map<Node, int, hash_name>map;
map[n1] = 1;
map[n2] = 2;
map[n3] = 3;
map[n4] = 4;
for (auto h : map){
cout << h.first.letter << "->" << h.second << endl;
}
}
unordered_map相关函数与hash_map相关函数用法差不多。在我参考的文章里面有。这下以后就可以顺利的使用哈希了。以后要是新学了再继续补充。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。