STL之 hash_set

       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当中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

世纪殇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值