(JohnZero)C++:unordered_set

简介

unordered_set 容器类型的模板定义在 unordered_set 头文件中。unordered_set 容器提供了和 unordered_map 相似的能力,但 unordered_set 可以用保存的元素作为它们自己的键。T 类型的对象在容器中的位置由它们的哈希值决定,因而需要定义一个 Hash 函数。

这种容器不能存放重复的元素。元素类型必须可以比较是否相等,因为这可以确定元素什么时候相等。就像 uordered_map,元素被存放在哈希表内部的格子中。每个格子保存哪个元素,是由元素的哈希值决定的。

c++ std中set与unordered_set区别和map与unordered_map区别类似:
set基于红黑树实现,红黑树具有自动排序的功能,因此map内部所有的数据,在任何时候,都是有序的。
unordered_set基于哈希表,数据插入和查找的时间复杂度很低,几乎是常数时间,而代价是消耗比较多的内存,无自动排序功能。底层实现上,使用一个下标范围比较大的数组来存储元素,形成很多的桶,利用hash函数对key进行映射到不同区域进行保存。

unordered_set容器完全攻略

http://c.biancheng.net/view/7250.html

C++官网

http://www.cplusplus.com/reference/unordered_set/unordered_set/

实例

#include<iostream>
#include<string>
#include<unordered_set>
using namespace std;
int main()
{
    string str = "abcd";
    unordered_set<char>uset;
    for (int i = 0; i < str.size(); ++i)
        uset.insert(str[i]);    //插入某元素
    bool a = uset.count('c');   //判断是否含有某元素
    cout << a << endl;      
    uset.erase('b');            //删除某元素
    for (auto it = uset.begin(); it != uset.end(); ++it)
        cout << *it;
}

输出结果:
1
acd
find:遍历寻找

unordered_set<int>uset = { 1,2,3,4,5 };
if (uset.find(4) != uset.end())
{
	cout << "find";
}
else cout << "not find";

微信

在这里插入图片描述
set使用时设置:
我们需要有序数据(不同的元素)。
我们必须打印/访问数据(按排序顺序)。
我们需要元素的前身/后继者。

在以下情况下使用unordered_set:
我们需要保留一组不同的元素,不需要排序。
我们需要单个元素访问,即没有遍历。

hash_set是非标准的,
而unordered_set是标准的

unordered_set
搜索、插入和移除
拥有平均常数时间复杂度

在内部,
元素并不以任何特别顺序排序,
而是组织进桶中。
元素被放进哪个桶完全依赖其值的哈希。
这允许对单独元素的快速访问,
因为哈希一旦确定,
就准确指代元素被放入的桶。

不可修改容器元素
(即使通过非 const 迭代器),
因为修改可能更改元素的哈希,
并破坏容器。

空:
unordered_set< int > my_set;
cout<<“size…”<<my_set.size()<<endl;
输出:
size…0

通过{}初始化:
unordered_set< int > my_set={11,22,33};
cout<<“size…”<<my_set.size()<<endl;
输出:
size…3

利用已有的set初始化
unordered_set< int > my_set={11,22,33};
unordered_set< int > my_set2=my_set;
unordered_set< int > my_set3(my_set);
cout<<“size…”<<my_set2.size()<<endl;
cout<<“size…”<<my_set3.size()<<endl;

使用迭代器初始化:
unordered_set< int > my_set={11,22,33};
unordered_set< int >
my_set2(my_set.begin(),my_set.end());
cout<<“size…”<<my_set2.size()<<endl;

通过vector,string的迭代器初始化:
string str=“abcdabcd”;
vector< int > my_vec={1,2,3};
unordered_set< int >
my_set2(str.begin(),str.end());
unordered_set< int > my_set3(my_vec.begin(),my_vec.end());
cout<<“size…”<<my_set2.size()<<endl;
cout<<“size…”<<my_set3.size()<<endl;
输出:
size…4
size…3
***123

不能通过unordered_map的迭代器初始化:
unordered_map<int,int> my_map;
my_map[1]=1;
unordered_set< int >
my_set(my_map.begin(),my_map.end());
cout<<“size…”<<my_set.size()<<endl;
编译报错:
no known conversion for argument 1
from ‘std::pair<const int, int>’
to ‘const
value_type& {aka const int&}’

遍历:
unordered_set < int > my_set={11,2,3,14,25,36,77,18,29, 11,2,3,14,25,36,77,18,29};
for(auto
it=my_set.begin();it!=my_set.end();++it)
{
cout<<*it<<endl;
}
输出:
29
18
77
36
25
14
3
2
11

没有顺序,既不是顺序,也不是逆序
unordered_set< int > my_set={3873, 9101, 2764, 3909, 5431, 1709, 3587, 4562, 1905, 9217};
for(auto
it=my_set.begin();it!=my_set.end();++it)
{
cout<<*it<<endl;
}
输出:
9217
1905
4562
5431
2764
1709
3909
9101
3587
3873

empty
size
max_size
代码:
unordered_set< int > my_set={3873, 9101};
cout<<“empty…”<<my_set.empty()<<endl;
cout<<“size…”<<my_set.size()<<endl;
cout<<“max_size…”<<my_set.max_size()<<endl;
输出:
empty…0
size…2
max_size…1152921504606846975

clear
insert
swap
extract–(C++17)
merge–(C++17)
count
find
contains(C++20)
equal_range

emplace
template <class… Args>
pair<iterator,bool> emplace
(Args&&… args);
其中,参数 (Args&&… args) 指的是,
只需要传入构建新元素所需的数据即可,
该方法可以自行利用这些数据构建出要添加的元素

emplace–返回值
返回值类型为 pair 类型,
其包含 2 个元素,
一个迭代器和一个 bool 值
●添加成功:
迭代器指向新插入的元素,
bool 值为 true;
●添加失败:
迭代器指向容器中具有相同键的这个元素,
同时 bool 值为 false

emplace–成功:
unordered_set< int > my_set;
auto x=my_set.emplace(99);
cout<<“size…”<<my_set.size()<<endl;
cout<<"*x.first…"<<*x.first<<endl;
cout<<“x.second…”<<x.second<<endl;
输出:
size…1
*x.first…99
x.second…1

emplace–失败:
unordered_set< int > my_set={22};
auto x=my_set.emplace(22);
cout<<“size…”<<my_set.size()<<endl;
cout<<"*x.first…"<<*x.first<<endl;
cout<<“x.second…”<<x.second<<endl;
输出:
size…1
*x.first…22
x.second…0

emplace_hint与emplace区别:
该方法需要额外传入一个迭代器,
用来指明新元素添加到 set 容器的具体位置
(新元素会添加到该迭代器指向元素的前面);

emplace_hint返回值:
返回值是一个迭代器,
而不再是 pair 对象。
●添加成功:
返回的迭代器指向新添加的元素;
●添加失败:
则迭代器就指向 set 容器和要添加元素的值相同的元素。

emplace_hint–成功:
unordered_set< int > my_set={11};
auto
x=my_set.emplace_hint(my_set.begin(),22);
cout<<“size…”<<my_set.size()<<endl;
cout<<"*x…"<<*x<<endl;

emplace_hint–失败:
unordered_set< int > my_set={22};
auto x=my_set.emplace_hint(my_set.begin(),22);
cout<<“size…”<<my_set.size()<<endl;
cout<<"*x…"<<*x<<endl;

erase
三个重载函数:

  1. 移除位于 pos 的元素。
  2. 移除范围 [first; last) 中的元素
  3. 移除关键等于 key 的元素(若存在一个)。

bucket_count
返回桶数
例子1:
unordered_set< int > my_set={1,2,3};
cout<<“bucket_count…”<<my_set.bucket_count()<<endl;
bucket_count…7
例子2:
unordered_set< int > my_set={3873, 9101, 2764, 3909, 5431, 1709, 3587, 4562, 1905, 9217};
cout<<“bucket_count…”<<my_set.bucket_count()<<endl;
bucket_count…11

max_bucket_count
返回桶的最大数量
unordered_set< int > my_set={1,2,3};
cout<<“max_bucket_count…”<<my_set.max_bucket_count()<<endl;
max_bucket_count…1152921504606846975

bucket_size
返回下标为 n 的桶中的元素数。
代码:
unordered_set< int > my_set={3873, 9101, 2764, 3909, 5431, 1709, 3587, 4562, 1905, 9217};
int bucket_count=my_set.bucket_count();
cout<<"…size…"<<my_set.size()<<endl;
for(int i=0;i<bucket_count;i++)
{
cout<<“i…”<<i<<"…size…"<<my_set.bucket_size(i)<<endl;
}
输出:
…size…10
i…0…size…0
i…1…size…2
i…2…size…1
i…3…size…1
i…4…size…3
i…5…size…0
i…6…size…0
i…7…size…0
i…8…size…2
i…9…size…0
i…10…size…1

bucket
返回关键 key 的桶的下标
代码:
unordered_set< int > my_set={3873, 9101, 2764, 3909, 5431, 1709, 3587, 4562, 1905, 9217};
cout<<"…size…"<<my_set.size()<<endl;
for(auto it=my_set.begin();it!=my_set.end();++it)
{
cout<<"*it…"<<*it<<endl;
cout<<“bucket…”<<my_set.bucket(*it)<<endl;
}
输出:
*it…9217
bucket…10
*it…1905
bucket…2
*it…4562
bucket…8
*it…5431
bucket…8
*it…2764
bucket…3
*it…1709
bucket…4
*it…3909
bucket…4
*it…9101
bucket…4
*it…3587
bucket…1
*it…3873
bucket…1
可以看到:
4562,5431都在8这个bucket里面
3587,3873都在1这个bucket里面
1709,3909,9101都在4这个bucket里面

load_factor
float load_factor() const;
返回每个桶的平均元素数量
即 size() 除以
bucket_count()
代码:
unordered_set< int > my_set={1,2,3};
cout<<“load_factor…”<<my_set.load_factor()<<endl;
cout<<“size/bucket_count…”<<1.0f*my_set.size()/my_set.bucket_count()<<endl;
输出:
load_factor…0.428571
size/bucket_count…0.428571

max_load_factor–111–返回最大加载因子
float max_load_factor() const
代码1:
unordered_set< int > my_set={1,2,3};
cout<<“max_load_factor…”<<my_set.max_load_factor()<<endl;
max_load_factor…1
代码2:
unordered_set< int > my_set={3873,
9101, 2764, 3909, 5431, 1709, 3587, 4562, 1905, 9217};
cout<<“max_load_factor…”<<my_set.max_load_factor()<<endl;
max_load_factor…1

max_load_factor—222—设置最大加载因子
void max_load_factor( float ml );
代码:
unordered_set< int > my_set={1,2,3};
cout<<“max_load_factor…”<<my_set.max_load_factor()<<endl;
my_set.max_load_factor(99);
cout<<“max_load_factor…”<<my_set.max_load_factor()<<endl;
输出:
max_load_factor…1
max_load_factor…99

rehash
void rehash( size_type count );
设置桶数为 count 并重哈希容器
若新的桶数使加载因子大于最大加载因子
( count < size() / max_load_factor() ),
则新桶数至少为 size() / max_load_factor()

rehash–例子:
unordered_set< int > my_set={3873, 9101, 2764, 3909, 5431, 1709, 3587, 4562, 1905, 9217};
cout<<“bucket_count…”<<my_set.bucket_count()<<endl;
my_set.rehash(100);
cout<<“bucket_count…”<<my_set.bucket_count()<<endl;
输出:
bucket_count…11
bucket_count…103

rehash—素数
my_set.rehash(500)–503
my_set.rehash(1024)–1031
my_set.rehash(256)–257
my_set.rehash(77)–79
不同版本的stl实现不一样,

reserve
void reserve( size_type count );
设置桶数为适应至少 count 个元素,
而不超出最大加载因子所需的数,
并重哈希容器
等价于调用:
rehash(std::ceil(count / max_load_factor())) 。

hash_function
hasher hash_function() const;
返回对关键哈希的函数。
hash_function–示例1:
unordered_set< int > my_set={1,2,3};
int key=1234567;
cout<<“key…”<<key<<endl;
cout<<“hash…”<<my_set.hash_function()(key)<<endl;
输出:
key…1234567
hash…1234567
对于正的int直接返回原样

hash_function–示例2:
unordered_set my_set={1,2,3};
long key=123456789012345678L;
cout<<“key…”<<key<<endl;
cout<<“hash…”<<my_set.hash_function()(key)<<endl;
输出:
key…123456789012345678
hash…123456789012345678
对于正的long直接返回原样

hash_function–示例3:
long key=-123456789012345678L;
输出:
key…-123456789012345678
hash…18323287284697205938
负数就不是原样了

hash_function–示例4:
unordered_set my_set;
string key=“aaa”;
cout<<“key…”<<key<<endl;
cout<<“hash…”<<my_set.hash_function()(key)<<endl;
输出:
key…a
hash…4993892634952068459
key…aa
hash…468926534229516570
key…aaa
hash…16343632196508755401

key_eq
key_equal key_eq() const;
返回比较关键相等性的函数。

erase_if
(C++20 起)
从容器中擦除所有满足谓词 pred 的元素

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值