hash_set是一种使用hash表数据结构的具有高效数据检索的关联容器,作为一种集合容器,他的元素不论有多少个分量,都作为一个单一的数据类型,元素的键值就是元素本身使用hash函数。
关于hash_set模式,我们必须知道hash_set的插入操作,插入的值是必须是唯一的inert_unique函数,根据元素值的大小按照某个函数式子直接计算得到元素的哈希地址,进行存储
SGI C++ STL哈希表是一个链式的结构,有表头和一系列的单链组成,表头呢是一个数组试的线性表,使用vector泛化出来,每个表头节点又称之为bucket,是一个指针域,指向的是链人的元素数据,一般而言每个机器上的桶的数目是确定的,同时不能更改的。笔者的是8,直接输出bucket_count()即可。也就是说该bucket(vector)共有元素8个,从0到7号,每次添加新元素的时候,通过hash函数的计算得到值,再对8进行求余(获得桶号),然后再进行比较,看看hash_set中是否有该元素,如果可以插入,则进行操作,不可以,则不进行插入。
// hash_set.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<hash_set>
#include<iostream>
#include <iterator>
using namespace std;
struct strequal{
static const size_t bucket_size = 95;
//表示是否可以插入,如果为真则可以插入,为假,则不能插入
bool operator() (const char* a,const char* b) const{
return strcmp(a,b)!=0;
}
//哈希函数对象
size_t operator( )( const char* Key ) const
{
return (int)(*Key)%3;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
hash_set<const char*,strequal> hs;
char* he="dasda";
char* dsa="dsads";
hs.insert(he);
hs.insert(he);
hs.insert(dsa);
hash_set<const char*,strequal>::iterator itr=hs.find(he);
cout<<*itr;
int count=0;
cout<<hs.bucket_count()<<endl;
for(hash_set<const char*,strequal>::iterator itr=hs.begin();itr!=hs.end();itr++)
{
cout<<count++<<":"<<*itr<<endl;
}
return 0;
}
这里面需要注意的是,在比较哈希对象strequal当中对于元素必须添加约束const,在函数之后也要添加约束 const,防止修改,对于哈希函数对象则要返回size_t确定放在哪一
个bucket当中去,我在进行尝试过程中遇到一个问题
1> with
1> [
1> _Mylist=std::_List_val<char *,std::allocator<char *>>
1> ]
1> and
1> [
1> _Mylist=std::_List_val<const char *,std::allocator<const char *>>
1> ]
1> 无构造函数可以接受源类型,或构造函数重载决策不明确
1>c:\users\jingmin\desktop\吴青老师\hash_set\hash_set\hash_set.cpp(35): error C2678: 二进制“!=”: 没有找到接受“std::_List_const_iterator<_Mylist>”类型的左操作数的运算符(或没有可接受的转换)
1> with
1> [
1> _Mylist=std::_List_val<const char *,std::allocator<const char *>>
1> ]
1> d:\program files\microsoft visual studio 10.0\vc\include\system_error(425): 可能是“bool std::operator !=(const std::error_code &,const std::error_condition &)”
1> d:\program files\microsoft visual studio 10.0\vc\include\system_error(432): 或 “bool std::operator !=(const std::error_condition &,const std::error_code &)”
1> d:\program files\microsoft visual studio 10.0\vc\include\list(298): 或 “bool std::_List_const_iterator<_Mylist>::operator !=(const std::_List_const_iterator<_Mylist> &) const”
1> with
1> [
1> _Mylist=std::_List_val<const char *,std::allocator<const char *>>
1> ]
1> 尝试匹配参数列表“(std::_List_const_iterator<_Mylist>, std::_List_const_iterator<_Mylist>)”时
1> with
1> [
1> _Mylist=std::_List_val<const char *,std::allocator<const char *>>
1> ]
1> and
1> [
1> _Mylist=std::_List_val<char *,std::allocator<char *>>
1> ]
出现这样的错误,一般是由于声明的数据类型和插入的数据类型不一致导致的例如
hash_set< char*,strequal> hs;
我是这样声明的,但是我是这样插入的
hs.insert("dsa");
就会出现上面的错误,问题原因在于实际插入的数据类型是 const char* 声明的却是 char*这就导致了,数据类型不一致的问题,大家在使用的时候还是要注意的最后在strequal当中声明了static size_t bucket_size;还是静态的变量,虽然知道这是确定bucket的数目的,但是还是不知道应该怎么进行修改这个数目...
另外就是bool operator()函数,个人理解是,返回值确定了该值是否可以插入,如果返回真都是真,则进行插入操作,如果其中有false返回值,则不进行插入操作
现在说下hash_set的结构:
由于hash_set是表头构成的多个单链构成(单链的数目我们称之为桶的数量),在实际应用中,如果桶的数目过程,则会浪费掉不必要的空间,然而如若 ,桶的数目过短则会造成每个桶下挂的数据数量过多,在进行数据查找时比较次数过多,效率过低,所以我们采用了一个28个质数元素的数组
static const unsigned long __stl_prime_list[_S_num_primes] =
{
53ul, 97ul, 193ul, 389ul, 769ul,
1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
1610612741ul, 3221225473ul, 4294967291ul
};
当我们初始化哈希表的表长的时候,一般用估计的方式得到元素个数n,通过一个stl_next_prime函数从上述数组中得到第一个不小于n的质数作为表长的大小
hash_set<int>hs() 他的默认哈希表长是193,
hash_set<int> hs(90)他的第一个不小于90 的质数为97,所以他的表长是97
对于hash_set本身是不允许插入重复的值的
struct myhash
{
size_t operator()(int x) const
{
return x+2;
}
};
hash_set<int,myhash()> hs(300,myhash());
这是hash_set的另外一种初始化过程:其中指定了hash_set的哈希函数对象,该对象的时候就是根据传入的值,重新进行计算上述hs的表长度是389,而每次进行插入时进行选择桶的时候就会根据myhash进行重新分配,也即当insert(21)时,会得到23,也即分配到23号桶当中。这里面我们只需要注意两点,其一该函数的返回值是size_t,其二该函数就是重载了一下()
struct strequal{
static const size_t bucket_size = 95;
//表示是否可以插入,如果为真则可以插入,为假,则不能插入
bool operator() (const char* a, const char* b) const{
return strcmp(a, b) != 0;
}
//哈希函数对象
size_t operator( )(const char* Key) const
{
return (int)(*Key) % 3;
}
};
hash_set<const char*, strequal> hs;
这下同时指定了hash_set中的元素类型是const char* ,比较函数和哈希对象函数都在strequal当中