散列容器(hash container)是一种非常重要的容器类型,它通常比二叉树的存储方式可以提供更高的访问效率。因为散列容器是无序的,因此不需要容器提供operator<,而是使用散列函数和键值比较的operator==,比标准容器的要求略微放宽一些。
unordered库提供两个散列集合类unordered_set和unordered_multiset,它们的用法接口和用法与C++标准里的关联容器set/multiset相同,只是内部使用散列表代替二叉树实现,因此查找复杂度由对数将为常数。
下面给出unordered_set的基本大的框架,其实是并没有这么简单的。。。。。
上述的图中只是给出了主的大框架,还有很多的类其实没有给出例如hash_node类,hash_node_constructor类等等并没有在图中体现。
首先给出unordered_set
T代表了键值类型,
H代表散列函数,该类里面默认使用boost::hash,
P代表键值的比较,默认使用std::equal_to<>
A代表空间配置器,默认使用系统的空间配置器。
从上图可以看出,unordered_set类将类hash_unique_table的对象作为自己的数据成员,实现了类与类之间的通信,然而类hash_unique_table继承与hash_table,hash_table类继承与hash_buckets,hash_buffered_functions类,从大的框架来看各个类的功能都很明确.
针对类unordered_set大概有以下的接口函数:
(1)begin:指定受控序列的开头。(返回为普通迭代器)
(2)end:指定受控序列的结尾。(同样返回为普通迭代器)
(3)cbegin:同样返回受控序列的开头。(返回为常量迭代器)
(4)cend:返回受控序列的结尾。(返回为常量迭代器)
(5)empty:检测元素是否存在。
(6)size:对元素进行计数。
(7)max_size:获取受控序列的最大大小。
(8)emplace:添加就地构造的元素。
emplace直接用参数构造元素并放入容器,返回值为一个对组(std::pair
(9)emplace_hint:同样也是构造元素,与emplace不同的是,emplace_hint要求提供一个迭代器的位置,表明元素要求插入到这个位置之后。同样其参数可以是一个,也可以是多个。
(10)insert(插入方法):
插入方法中提供了很多中的方式:
(a):单个元素插入,返回对组
std::pair
(b):提供位置进行插入,返回迭代器
iterator insert(const_iterator,const value_type& obj);
(c):将一个范围的值进行插入
void insert(InputIt first,InputIt last);
(11)erase(删除方式):
删除方式也提供了很多种:
(a):删除某一位置的元素
iterator erase(const_iterator position)
(b):删除某一个key值,返回删除的个数:
size_type erase(const key_value& k)
(c):按范围删除元素
iterator erase(const_iterator first,const_iterator last)
(d):删除某一位置的元素
void quick_erase(const_iterator position)
(12)clear:清空内容
(13)hash_function:返回hash函数
(14)key_eq:返回主键等价性判断谓词
(15)find:通过给定主键查找元素
const_iterator find(const key_type& k)const
(16)count:返回匹配给定主键的元素的个数
size_type count(const key_type& k)const
(17)equal_range:返回值匹配给定搜索值的元素组成的范围
std::pair
equal_range(const key_value& k)const
(18)load_factor:返回载入因子,即一个元素槽的最大元素值
float load_factor()const
(19)max_load_factor:返回或设置最大的载入因子
void max_load_factor(float m)
(20)rehash:设置槽数
void rehash(size_type n)
(21)reverse:请求改变容器的容量
上图也向大家展示了类unordered_set的内部结构。。。
下面给出一些实例:
(1):
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace boost;
typedef complex complex_t;
#if 0
int main(int argc,char *argv[])
{
//创建对象,并进行初始化
unordered_set s = (boost::assign::list_of(1),2,3,4,5);
//使用迭代器进行遍历
for(BOOST_AUTO(p,s.begin()); p != s.end(); ++p)
cout << *p << " ";
cout << endl;
//获取元素的个数
cout << "s.size = " << s.size() << endl;
//判断集合是否为空
cout << "is empty " << s.empty() << endl;
//插入元素
s.insert(8);
s.insert(45);
for(BOOST_AUTO(p,s.begin()); p != s.end(); ++p)
cout << *p << " ";
cout << endl;
//查找元素
s.find(45);
//获取元素的个数
cout << "s.size = " << s.size() << endl;
//查找元素
cout << "find vaule 8 " << *s.find(8) << endl;
//删除元素45
s.erase(45);
for(BOOST_AUTO(p,s.begin()); p != s.end(); ++p)
cout << *p << " ";
cout << endl;
cout << "bucket_count:" << s.bucket_count() << endl;
cout << "max_bucket_count:" << s.max_bucket_count() << endl;
cout << "bucket_size:" << s.bucket_size(0) << endl;
cout << "load_factor:" << s.load_factor() << endl;
cout << "max_load_factor:" << s.max_load_factor() << endl;
//清空集合
s.clear();
return 0;
}
#endif
(2):
#if 0
int main(int argc,char*argv[])
{
unordered_set s;
s.emplace(1.0,2.0);
s.emplace(3.0,4.0);
for(BOOST_AUTO(p,s.begin()); p != s.end(); ++p)
cout << *p << " ";
cout << endl;
cout << "s.size = " << s.size() << endl;
s.emplace_hint(s.begin(),5.0,6.0);
for(BOOST_AUTO(p,s.begin()); p != s.end(); ++p)
cout << *p << " ";
cout << endl;
return 0;
}
#endif
(3):
#if 1
int main(int argc,char* argv[])
{
unordered_set us = (boost::assign::list_of(1),2,3,4,5,6,7);
cout << "bucket_count = " << us.bucket_count() << endl;
for(int i = 0; i < us.bucket_count(); ++i)
{
cout << us.bucket_size(i) << ","; //访问每一个桶
}
cout << endl;
return 0;
}
#endif
unordered库使用“桶”(bucket)来存储元素,散列值相同的元素放入同一个桶中。当散列容器的桶的数量可以用函数bucket_count()来获得,bucket_size()返回桶中的元素数量。当散列容器中有大量的数据时,桶中的元素数量也会增多,会造成访问冲突。为了提高散列容器的性能,unordered库会在插入元素时自动增加桶的数量。用户不能直接指定桶的数量(由散列容器自己管理会更好),但可以在构造函数或者rehash()函数指定最小的桶的数量。散列容器还有一个函数max_load_factor(),它可以获取或设定散列容器的最大的负载因子,即桶中元素的最大平均数量。通常最大的负载因子都是1。。。。