unordered_set和unordered_map的使用【STL】

1. unordered系列关联式容器

在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查找时效率可达到 O ( l o g 2 N ) O(log_2 N) O(log2N),即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查找效率也不理想。效率最高的查找方式是:进行很少的比较次数就能够将元素找到,因此在C++11中,STL又提供了4个unordered系列的关联式容器,这四个容器与红黑树结构的关联式容器使用方式基本类似,只是其底层结构不同。

实际上,unordered_map和unordered_set从名字看来,它储存的元素是unordered(无序的),而在使用上大体和set和map并无二致。

不同的是,unordered系列的容器使用了哈希结构,这也是它们存储的元素不在有序的原因。由于STL良好的封装,使得即使底层实现不同,但上层使用上还是类似的。

友情链接:map和set

unordered的命名的历史背景:

如果在现在看来,包括Java标准库也是这样设计的:根据底层实现方式的不同,set和map都以设计结构为前缀,例如:TreeMap、TreeSet;HashMap、HashSet等。

C++标准库在早期并没有将哈希结构的map和set另外作为一类容器,而是将以红黑树为底层结构的map和set作为内置容器,原因是当时计算机的CPU的算力和实际数据量还无需使用查找效率更高的哈希结构封装的map和set。但是已经推出的标准无法改变,C++的某个语言标准中提出了增加hash_*类模板,最终接受为unordered_*

2. unordered_set

2.1 unordered_set的介绍

  • unordered_set是存储<key, value>键值对的关联式容器,其允许通过key值快速的索引到与其对应的value值;键值key通常用于唯一地标识元素,而value值是一个对象,它的内容和键值key关联;
  • unordered_set没有对<key, value>按照任何特定的顺序排序,为了能在常数范围内找到key所对应的value,unordered_set将相同哈希值的键值对放在相同的桶中;
  • unordered_set容器通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭代方面效率较低;
  • 它只有单向迭代器。

2.2 unordered_set的使用

unordered_set的模板参数列表

头文件

#include <unordered_set>

模板参数列表

template<
    class Key,
    class T,
    class Hash = std::hash<Key>,
    class KeyEqual = std::equal_to<Key>,
    class Allocator = std::allocator< std::pair<const Key, T> >
> class unordered_map;
  • Key:容器中存储元素的类型;
  • Hash:确定元素存储位置所用的哈希函数;
  • KeyEqual:判断各个元素是否相等所用的函数;
  • Allocator:指定分配器对象的类型(暂不做了解)。
参数含义
Key确定容器存储元素的类型,如果将unordered_set看做是存储键和值相同的键值对的容器,则此参数则用于推导各个键值对的键和值的类型,因为它们是完全相同的,因此一定是同一数据类型的数据。
Hash=hash<Key>指定unordered_set容器底层存储各个元素时,所使用的哈希函数。需要注意的是,默认哈希函数hash<Key>只适用于基本数据类型(包括 string 类型),而不适用于自定义类型。
Pred=equal_to<Key>unordered_set容器内部不能存储相同的元素,而衡量2个元素是否相等的标准,取决于该参数指定的函数。默认情况下,使用STL标准库中提供的equal_to<key>规则,该规则仅支持可直接使用==运算符做比较的数据类型。

unordered_set的构造器

函数声明功能
unordered_set(size_type()) {}构造空的unordered_set容器
unordered_set ( InputIterator first, InputIterator last);用[first, last)区间中的元素构造 unordered_set
unordered_set( unordered_set&& other );unordered_set的拷贝构造

示例:

void unordered_set_test1()
{
	unordered_set<int> us1;							 // 构造int类型的空容器

	string str = "hello world";
	unordered_set<char> us2(str.begin(), str.end()); // 使用迭代器区间构造
	
	unordered_set<int> us3(us1);					 // 拷贝构造
}

unordered_set常用接口

成员方法功能
empty()若容器为空,则返回true;否则false。
size()返回当前容器中存有元素的个数。
max_size()返回容器所能容纳元素的最大个数,不同的操作系统,其返回值亦不相同。
find(key)查找以值为key的元素,如果找到,则返回一个指向该元素的正向迭代器;反之,则返回一个指向容器中最后一个元素之后位置的迭代器(如果end()方法返回的迭代器)。
count(key)在容器中查找值为key的元素的个数。
equal_range(key)返回一个pair对象,其包含2个迭代器,用于表明当前容器中值为key的元素所在的范围。
emplace()向容器中添加新元素,效率比insert()方法高。
emplace_hint()向容器中添加新元素,效率比insert()方法高。
insert()向容器中添加新元素。
erase()删除指定元素。
clear()清空容器,即删除容器中存储的所有元素。
swap()交换2个unordered_set容器存储的元素,前提是必须保证这2个容器的类型完全相等。
bucket_count()返回当前容器底层存储元素时,使用桶(一个线性链表代表一个桶)的数量。
max_bucket_count()返回当前系统中,unordered_set 容器底层最多可以使用多少桶。
bucket_size(n)返回第n个桶中存储元素的数量。
bucket(key)返回值为key的元素所在桶的编号。
load_factor()返回unordered_set容器中当前的负载因子。负载因子,指的是的当前容器中存储元素的数量(size())和使用桶数(bucket_count())的比值,即 load_factor() = size() / bucket_count()。
max_load_factor()返回或者设置当前unordered_set容器的负载因子。
rehash(n)将当前容器底层使用桶的数量设置为n。
reserve()将存储桶的数量(也就是bucket_count()方法的返回值)设置为至少容纳count个元(不超过最大负载因子)所需的数量,并重新整理容器。
hash_function()返回当前容器使用的哈希函数对象。

迭代器相关

成员方法功能
begin()返回指向容器中第一个元素的正向迭代器。
end();返回指向容器中最后一个元素之后位置的正向迭代器。
cbegin()和begin()功能相同,只不过其返回的是const类型的正向迭代器。
cend()和end()功能相同,只不过其返回的是const类型的正向迭代器。

unordered_set没有反向迭代器。

示例

void unordered_set_test2()
{
	unordered_set<int> us;

	us.insert(1);
	us.insert(1); // 去重
	us.insert(2);
	us.insert(5);
	us.insert(4);
	us.insert(3);
	us.insert(6);

	for (auto e : us) // 使用范围for遍历
	{
		cout << e << " ";
	}
	cout << endl;

	unordered_set<int>::iterator pos = us.find(2); // 找到key为2的位置
	us.erase(pos);								   // 删除key为2的元素
	unordered_set<int>::iterator it = us.begin();
	while (it != us.end())						  // 迭代器遍历 
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	

	cout << us.count(1) << endl; // 容器中key为1的元素个数

	cout << us.size() << endl; // 容器中元素的个数、

	us.clear(); // 清空容器

	cout << us.empty() << endl;
}

输出

1 2 5 4 3 6
1 5 4 3 6
1
5
1

3. unordered_multiset

unordered_multiset和unordered_set的唯一区别是它允许键值冗余,即可以储存key值重复的元素。因此,两种容器的find和count的意义也有所区别。

3.1 成员函数的区别

find

find功能
unordered_set返回key值为x的元素的迭代器
unordered_multiset返回哈希表中第一个key值为x的元素的迭代器

count

count功能
unordered_set键值key为x的元素存在则返回1,不存在则返回0
unordered_multiset返回键值key为x的元素个数

3.2 示例

void unordered_multiset_test()
{
	unordered_multiset<int> ums;

	ums.insert(1);
	ums.insert(1);
	ums.insert(2);
	ums.insert(7);
	ums.insert(5);
	ums.insert(4);
	ums.insert(2);

	for(auto e : ums)
	{
		cout << e << " ";
	}
	cout << endl;

}

输出

4 5 2 2 7 1 1

4. unordered_map

4.1 unordered_map的介绍

通过查阅官方文档们可以知道unordered_map的特性:

  • unordered_map是存储<key, value>键值对的关联式容器,其允许通过key值快速的索引到与其对应的value值;键值key通常用于唯一地标识元素,而value值是一个对象,它的内容和键值key关联;

  • unordered_map没有对<key, value>按照任何特定的顺序排序,为了能在常数范围内找到key所对应的value,unordered_map将相同哈希值的键值对放在相同的桶中;

  • unordered_map容器通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭代方面效率较低;

  • unordered_map实现了直接访问操作符(operator[]),它允许使用key作为参数直接访问value;

  • 它只有单向迭代器。

4.2 unordered_map的使用

unordered_map的参数列表

头文件

#include <unordered_map>

模板参数列表

template<
    class Key,
    class T,
    class Hash = std::hash<Key>,
    class KeyEqual = std::equal_to<Key>,
    class Allocator = std::allocator< std::pair<const Key, T> >
> class unordered_map;
  • Key:容器中存储元素的类型;
  • Hash:确定元素存储位置所用的哈希函数;
  • KeyEqual:判断各个元素是否相等所用的函数;
  • Allocator:指定分配器对象的类型(暂不做了解)。

unordered_map的构造器

函数声明功能介绍
unordered_map (const Compare& comp = Compare(), const Allocator& = Allocator());构造空的unordered_map
unordered_map (InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator() ); 用[first, last)区 间中的元素构造 unordered_map
unordered_map (const map<Key,Compare,Allocator>& x);unordered_map的拷贝构造

示例:

void unordered_map_test()
{
	unordered_map<int, string> um1; // 构造一个键值对为<int, string>的空容器

	unordered_map<int, string> um2(um1.begin(), um1.end()); // 迭代器区间构造

	unordered_map<int, string> um3(um1); // 拷贝构造
}

unordered_map的常用接口

函数声明功能
pair<iterator,bool> insert ( const value_type& x )在map中插入键值对x,注意x是一个键值对,返回值也是键值对。iterator代表新插入元素的位置,bool代表插入成功。
void erase ( iterator position )删除position位置的元素
size_type erase ( const key_type& x )删除键值key为x的元素,返回删除元素的个数
void erase ( iterator first, iterator last )删除[first, last)之间所有元素
iterator find ( const key_type& x )查找键值key为x的元素,找到则返回该元素的迭代器,否则返回end()
const_iterator find ( const key_type& x ) const查找键值key为x的元素,找到则返回该元素的const迭代器,否则返回cend()
size_type size() const返回unordered_map容器中有效元素的个数
bool empty ( ) const判断unordered_map容器是否为空
void clear ( )清空unordered_map容器
void swap ( unordered_map<Key,T,Compare,Allocator>& mp )交换两个unordered_map容器的数据
size_type count ( const key_type& x ) const返回键值key为x的元素的个数
mapped_type& operator[] (const key_type& k)返回键值key为x对应的value

在常用的接口中,unordered_map新增了一个操作符[],它可以根据传入的key找到对应的value。

[key]表示返回key对应的value的==引用==,所以我们不仅可以通过operator[]查找,还能修改key对应的value。

  • 如果key不存在:operator[]会调用默认构造函数创建一个匿名对象用来构造一个pair,然后插入,接着才会返回它的引用;
  • 如果key存在:返回键值为key的元素对应的pair对象的引用。

迭代器相关

成员函数功能
iterator begin()获取容器中第一个元素的正向迭代器
iterator end()获取容器中最后一个元素下一个位置的正向迭代器
const_iterator cbegin()同上,但是不能修改迭代器对应的元素
const_iterator end()同上,但是不能修改迭代器对应的元素

unordered_map没有反向迭代器。

示例

void unordered_map_test2()
{
	unordered_map<int, string> um;
	um.insert(make_pair(1, "一"));
	um.insert(make_pair(2, "二"));
	um.insert(make_pair(3, "三"));
	um.insert(make_pair(4, "四"));

	// 迭代器遍历
	unordered_map<int, string>::iterator it = um.begin();
	while (it != um.end())
	{
		cout << "<" << it->first << ", " << it->second << ">" << endl;
		it++;
	}
	cout << endl;

	// 删除key=2的元素
	um.erase(2);

	for (auto e : um)
	{
		cout << "<" << e.first << ", " << e.second << ">" << endl;
	}
	cout << endl;

	// 查找key=3的元素
	auto pos = um.find(3);
	if(pos != um.end())
	{
		cout << "<" << pos->first << ", " << pos->second << ">" << endl;
	}

	// 清空容器
	um.clear();
	// 容器判空
	cout << um.empty() << endl;
}

输出

<4, 四>

< 3, 三>

<2, 二>

<1, 一>

<4, 四>

< 3, 三>

<1, 一>

< 3, 三>

1

5. unordered_multimap

unordered_multimap容器与unordered_map容器的唯一区别就是它允许键值冗余,即unordered_multimap容器当中存储的键值对的key值是可以重复的。因此,两种容器的find和count的意义也有所区别。

5.1 成员函数的区别

find

find功能
unordered_map返回key值为x的元素的迭代器
unordered_multimap返回哈希表中第一个key值为x的元素的迭代器

count

count功能
unordered_map键值key为x的元素存在则返回1,不存在则返回0
unordered_multimap返回键值key为x的元素个数

5.2 示例

void unordered_multimap_test()
{
	unordered_multimap<int, string> umm;
	umm.insert(make_pair(1, "一"));
	umm.insert(make_pair(1, "first"));
	umm.insert(make_pair(1, "one"));
	for (auto e : umm)
	{
		cout << "<" << e.first << ", " << e.second << ">" << endl;
	}
	cout << endl;
}

输出

<1, 一>

<1, first>

<1, one>

posted @ 2022-12-06 22:31  shawyxy  阅读(189)  评论(0编辑  收藏  举报