set 容器定义于<set>
头文件,并位于 std 命名空间中。因此如果想在程序中使用 set 容器,该程序代码应先包含如下语句:
#include <set>
using namespace std;
set 容器的类模板定义如下:
template < class T, // 键 key 和值 value 的类型
class Compare = less<T>, // 指定 set 容器内部的排序规则
class Alloc = allocator<T> // 指定分配器对象的类型
> class set;
注意,由于 set 容器存储的各个键值对,其键和值完全相同,也就意味着它们的类型相同,因此 set 容器类模板的定义中,仅有第 1 个参数用于设定存储数据的类型。
1. set容器的创建
调用默认构造函数,创建空的 set 容器。比如:
std::set<std::string> myset;
set 类模板还支持在创建 set 容器的同时,对其进行初始化。例如:
std::set<std::int> myset{1, 2, 3, 4};
set 类模板中还提供了拷贝(复制)构造函数,可以实现在创建新 set 容器的同时,将已有 set 容器中存储的所有元素全部复制到新 set 容器中:
std::set<std::string> copyset(myset);
// 等同于
std::set<std::string> copyset = myset
该行代码在创建 copyset 容器的基础上,还会将 myset 容器中存储的所有元素,全部复制给 copyset 容器一份。
C++ 11 标准还为 set 类模板新增了移动构造函数,其功能是实现创建新 set 容器的同时,利用临时的 set 容器为其初始化。比如:
set<string> retSet() {
std::set<std::string> myset{1, 2, 3};
return myset;
}
std::set<std::string> copyset(retSet());
//或者
std::set<std::string> copyset = retSet();
注意:由于 retSet() 函数的返回值是一个临时 set 容器,因此在初始化 copyset 容器时,其内部调用的是 set 类模板中的移动构造函数,而非拷贝构造函数。
set 类模板还支持取已有 set 容器中的部分元素,来初始化新 set 容器。例如:
std::set<std::string> myset{1, 2, 3, 4};
std::set<std::string> copyset(++myset.begin(), myset.end());
以上几种方式创建的 set 容器,都采用了默认的std::less<T>
规则。其实,借助 set 类模板定义中第 2 个参数,我们完全可以手动修改 set 容器中的排序规则。比如:
std::set<std::string,std::greater<string> > myset{1, 2, 3, 4};
2. set成员函数
成员方法 | 功能 |
---|---|
begin() | 返回指向容器中第一个(注意,是已排好序的第一个)元素的双向迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
end() | 返回指向容器最后一个元素(注意,是已排好序的最后一个)所在位置后一个位置的双向迭代器,通常和 begin() 结合使用。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
rbegin() | 返回指向最后一个(注意,是已排好序的最后一个)元素的反向双向迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。 |
rend() | 返回指向第一个(注意,是已排好序的第一个)元素所在位置前一个位置的反向双向迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。 |
cbegin() | 和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。 |
cend() | 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。 |
crbegin() | 和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。 |
crend() | 和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。 |
find(val) | 在 set 容器中查找值为 val 的元素,如果成功找到,则返回指向该元素的双向迭代器;反之,则返回和 end() 方法一样的迭代器。另外,如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
lower_bound(val) | 返回一个指向当前 set 容器中第一个小于或等于 val 的元素的双向迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
upper_bound(val) | 返回一个指向当前 set 容器中第一个大于 val 的元素的迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
equal_range(val) | 该方法返回一个 pair 对象(包含 2 个双向迭代器),其中 pair.first 和 lower_bound() 方法的返回值等价,pair.second 和 upper_bound() 方法的返回值等价。也就是说,该方法将返回一个范围,该范围中包含的值为 val 的元素(set 容器中各个元素是唯一的,因此该范围最多包含一个元素)。 |
empty() | 若容器为空,则返回 true;否则 false。 |
size() | 返回当前 set 容器中存有元素的个数。 |
max_size() | 返回 set 容器所能容纳元素的最大个数,不同的操作系统,其返回值亦不相同。 |
insert() | 向 set 容器中插入元素。 |
erase() | 删除 set 容器中存储的元素。 |
swap() | 交换 2 个 set 容器中存储的所有元素。这意味着,操作的 2 个 set 容器的类型必须相同。 |
clear() | 清空 set 容器中所有的元素,即令 set 容器的 size() 为 0。 |
emplace() | 在当前 set 容器中的指定位置直接构造新元素。其效果和 insert() 一样,但效率更高。 |
emplace_hint() | 在本质上和 emplace() 在 set 容器中构造新元素的方式是一样的,不同之处在于,使用者必须为该方法提供一个指示新元素生成位置的迭代器,并作为该方法的第一个参数。 |
count(val) | 在当前 set 容器中,查找值为 val 的元素的个数,并返回。注意,由于 set 容器中各元素的值是唯一的,因此该函数的返回值最大为 1。 |
3. insert操作
3.1 方式一
只要给定目标元素的值,insert() 方法即可将该元素添加到 set 容器中,其语法格式如下:
// 普通引用方式传参
pair<iterator,bool> insert (const value_type& val);
// 右值引用方式传参
pair<iterator,bool> insert (value_type&& val);
其中,val 表示要添加的新元素,该方法的返回值为 pair 类型。
可以看到,以上 2 种语法格式的 insert() 方法,返回的都是 pair 类型的值,其包含 2 个数据,一个迭代器和一个 bool 值:
-
当向 set 容器添加元素成功时,该迭代器指向 set 容器新添加的元素,bool 类型的值为 true;
-
如果添加失败,即证明原 set 容器中已存有相同的元素,此时返回的迭代器就指向容器中相同的此元素,同时 bool 类型的值为 false。
#include <iostream>
#include <set>
#include <string>
using namespace std;
int main()
{
// 创建并初始化set容器
std::set<std::string> myset;
// 准备接受 insert() 的返回值
pair<set<string>::iterator, bool> retpair;
// 采用普通引用传值方式
string str = "http://c.biancheng.net/stl/";
retpair = myset.insert(str);
cout << "iter->" << *(retpair.first) << " " << "bool = " << retpair.second << endl;
// 采用右值引用传值方式
retpair = myset.insert("http://c.biancheng.net/python/");
cout << "iter->" << *(retpair.first) << " " << "bool = " << retpair.second << endl;
return 0;
}
3.2 方式二
insert() 还可以指定将新元素插入到 set 容器中的具体位置,其语法格式如下:
// 以普通引用的方式传递 val 值
iterator insert (const_iterator position, const value_type& val);
// 以右值引用的方式传递 val 值
iterator insert (const_iterator position, value_type&& val);
#include <iostream>
#include <set>
#include <string>
using namespace std;
int main()
{
// 创建并初始化set容器
std::set<std::string> myset;
// 准备接受 insert() 的返回值
set<string>::iterator iter;
// 采用普通引用传值方式
string str = "http://c.biancheng.net/stl/";
iter = myset.insert(myset.begin(),str);
cout << "myset size =" << myset.size() << endl;
// 采用右值引用传值方式
iter = myset.insert(myset.end(),"http://c.biancheng.net/python/");
cout << "myset size =" << myset.size() << endl;
return 0;
注意:使用 insert() 方法将目标元素插入到 set 容器指定位置后,如果该元素破坏了容器内部的有序状态,set 容器还会自行对新元素的位置做进一步调整。也就是说,insert() 方法中指定新元素插入的位置,并不一定就是该元素最终所处的位置。
3.3 方式三
insert() 方法支持向当前 set 容器中插入其它 set 容器指定区域内的所有元素,只要这 2 个 set 容器存储的元素类型相同即可。
template <class InputIterator>
void insert (InputIterator first, InputIterator last);
其中 first 和 last 都是迭代器,它们的组合 [first,last) 可以表示另一 set 容器中的一块区域,该区域包括 first 迭代器指向的元素,但不包含 last 迭代器指向的元素。
#include <iostream>
#include <set>
#include <string>
using namespace std;
int main()
{
//创建并初始化set容器
std::set<std::string> myset{ "http://c.biancheng.net/stl/",
"http://c.biancheng.net/python/",
"http://c.biancheng.net/java/" };
// 创建一个同类型的空 set 容器
std::set<std::string> otherset;
// 利用 myset 初始化 otherset
otherset.insert(++myset.begin(), myset.end());
// 输出 otherset 容器中的元素
for (auto iter = otherset.begin(); iter != otherset.end(); ++iter) {
cout << *iter << endl;
}
return 0;
}
3.4 emplace操作
template <class... Args>
pair<iterator,bool> emplace (Args&&... args);
另外,该方法的返回值类型为 pair 类型,其包含 2 个元素,一个迭代器和一个 bool 值:
-
当该方法将目标元素成功添加到 set 容器中时,其返回的迭代器指向新插入的元素,同时 bool 值为 true;
-
当添加失败时,则表明原 set 容器中已存在相同值的元素,此时返回的迭代器指向容器中具有相同键的这个元素,同时 bool 值为false;
#include <iostream>
#include <set>
#include <string>
using namespace std;
int main()
{
// 创建并初始化 set 容器
std::set<string>myset;
// 向 myset 容器中添加元素
pair<set<string, string>::iterator, bool> ret = myset.emplace("http://c.biancheng.net/stl/");
cout << "myset size = " << myset.size() << endl;
cout << "ret.iter = <" << *(ret.first) << ", " << ret.second << ">" << endl;
return 0;
}
3.5 emplace_hint操作
和 emplace() 方法相比,有以下 2 点不同:
-
该方法需要额外传入一个迭代器,用来指明新元素添加到 set 容器的具体位置(新元素会添加到该迭代器指向元素的前面);
-
返回值是一个迭代器,而不再是 pair 对象。当成功添加元素时,返回的迭代器指向新添加的元素;反之,如果添加失败,则迭代器就指向 set 容器和要添加元素的值相同的元素。
emplace() 、emplace_hint() 比insert() 效率高的原因:
-
使用 insert() 向 map / set 容器中插入键值对的过程是,先创建该键值对,然后再将该键值对复制或者移动到 map 容器中的指定位置;整个插入过程调用了 1 次类的构造函数,同时还调用了 2次移动构造函数。
-
使用 emplace() 或 emplace_hint() 插入键值对的过程是,直接在 map 容器中的指定位置构造该键值对。
template <class... Args>
iterator emplace_hint (const_iterator position, Args&&... args);
4. erase操作
如果想删除 set 容器存储的元素,可以选择用 erase() 或者 clear() 成员方法。
set 类模板中,erase() 方法有 3 种语法格式,分别如下:
// 删除 set 容器中值为 val 的元素
size_type erase (const value_type& val);
// 删除 position 迭代器指向的元素
iterator erase (const_iterator position);
// 删除 [first,last) 区间内的所有元素
iterator erase (const_iterator first, const_iterator last);
其中,第 1 种格式的 erase() 方法,其返回值为一个整数,表示成功删除的元素个数;后 2 种格式的 erase() 方法,返回值都是迭代器,其指向的是 set 容器中删除元素之后的第一个元素,如果要删除的元素就是 set 容器最后一个元素,则 erase() 方法返回的迭代器就指向新 set 容器中最后一个元素之后的位置(等价于 end() 方法返回的迭代器)。
如果需要删除 set 容器中存储的所有元素,可以使用 clear() 成员方法。该方法的语法格式如下:
void clear();
标签:std,容器,set,const,迭代,元素 From: https://www.cnblogs.com/love-9/p/18150951