set 容器
使用 set 容器存储的各个键值对,要求键 key 和值 value 必须相等。基于 set 容器的这种特性,当使用 set 容器存储键值对时,只需要为其提供各键值对中的 value 值(也就是 key 的值)即可。
使用 set 容器存储的各个元素的值必须各不相同。
切勿尝试直接修改 set 容器中已存储元素的值,这很有可能破坏 set 容器中元素的有序性,最正确的修改 set 容器中元素值的做法是:先删除该元素,然后再添加一个修改后的元素。
set 容器定义于<set>
头文件,并位于 std 命名空间中。
创建set容器的几种方法
-
调用默认构造函数,创建空的 set 容器:
std::set<std::string> myset;
该容器采用默认的
std::less<T>
规则,会对存储的 string 类型元素做升序排序。 -
在创建 set 容器的同时,对其进行初始化。
std::set<std::string> myset{"http://c.biancheng.net/java/", "http://c.biancheng.net/stl/", "http://c.biancheng.net/python/"};
-
在创建新 set 容器的同时,将已有 set 容器中存储的所有元素全部复制到新 set 容器中。
std::set<std::string> copyset(myset); //等同于 //std::set<std::string> copyset = myset
-
创建新 set 容器的同时,利用临时的 set 容器为其初始化。
set<string> retSet() { std::set<std::string> myset{ "http://c.biancheng.net/java/", "http://c.biancheng.net/stl/", "http://c.biancheng.net/python/" }; return myset; } std::set<std::string> copyset(retSet()); //或者 //std::set<std::string> copyset = retSet();
由于 retSet() 函数的返回值是一个临时 set 容器,因此在初始化 copyset 容器时,其内部调用的是 set 类模板中的移动构造函数,而非拷贝构造函数。
-
取已有 set 容器中的部分元素,来初始化新 set 容器。
std::set<std::string> myset{ "http://c.biancheng.net/java/", "http://c.biancheng.net/stl/", "http://c.biancheng.net/python/" }; std::set<std::string> copyset(++myset.begin(), myset.end());
-
手动修改 set 容器中的排序规则
std::set<std::string,std::greater<string> > myset{ "http://c.biancheng.net/java/", "http://c.biancheng.net/stl/", "http://c.biancheng.net/python/"};
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 |
#include <iostream>
#include <set>
#include <string>
using namespace std;
int main()
{
//创建空set容器
std::set<std::string> myset;
//空set容器不存储任何元素
cout << "1、myset size = " << myset.size() << endl;
//向myset容器中插入新元素
myset.insert("http://c.biancheng.net/java/");
myset.insert("http://c.biancheng.net/stl/");
myset.insert("http://c.biancheng.net/python/");
cout << "2、myset size = " << myset.size() << endl;
//利用双向迭代器,遍历myset
for (auto iter = myset.begin(); iter != myset.end(); ++iter) {
cout << *iter << endl;
}
return 0;
}
set容器迭代器
set 容器类模板中未提供 at() 成员函数,也未对 [] 运算符进行重载。因此,要想访问 set 容器中存储的元素,只能借助 set 容器的迭代器。
C++ STL 标准库为 set 容器配置的迭代器类型为双向迭代器。这意味着,假设 p 为此类型的迭代器,则其只能进行 ++p、p++、–p、p–、*p 操作,并且 2 个双向迭代器之间做比较,也只能使用 == 或者 != 运算符。
begin()/end()
#include <iostream>
#include <set>
#include <string>
using namespace std;
int main()
{
//创建并初始化set容器
std::set<std::string> myset{ "http://c.biancheng.net/java/",
"http://c.biancheng.net/stl/",
"http://c.biancheng.net/python/"
};
//利用双向迭代器,遍历myset
for (auto iter = myset.begin(); iter != myset.end(); ++iter) {
cout << *iter << endl;
}
return 0;
}
因为 iter 迭代器指向的是 set 容器存储的某个元素,而不是键值对,因此通过 *iter 可以直接获取该迭代器指向的元素的值。
如果只想遍历 set 容器中指定区域内的部分数据,则可以借助 find()、lower_bound() 以及 upper_bound() 实现。通过调用它们,可以获取一个指向指定元素的迭代器。
equal_range(val) 函数的返回值是一个 pair 类型数据,其包含 2 个迭代器,表示 set 容器中和指定参数 val 相等的元素所在的区域,但由于 set 容器中存储的元素各不相等,因此该函数返回的这 2 个迭代器所表示的范围中,最多只会包含 1 个元素。
#include <iostream>
#include <set>
#include <string>
using namespace std;
int main()
{
//创建并初始化set容器
std::set<std::string> myset{ "http://c.biancheng.net/java/",
"http://c.biancheng.net/stl/",
"http://c.biancheng.net/python/"
};
set<string>::iterator iter = myset.find("http://c.biancheng.net/python/");
for (;iter != myset.end();++iter)
{
cout << *iter << endl;
}
return 0;
}
set 类模板中包含 lower_bound()、upper_bound()、equal_range() 这 3 个成员函数,但它们更适用于 multiset 容器,几乎不会用于操作 set 容器。
set insert()方法
-
只要给定目标元素的值,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; }
-
insert() 还可以指定将新元素插入到 set 容器中的具体位置
//以普通引用的方式传递 val 值 iterator insert (const_iterator position, const value_type& val); //以右值引用的方式传递 val 值 iterator insert (const_iterator position, value_type&& val);
以上 2 种语法格式中,insert() 函数的返回值为迭代器:
- 当向 set 容器添加元素成功时,该迭代器指向容器中新添加的元素;
- 当添加失败时,证明原 set 容器中已有相同的元素,该迭代器就指向 set 容器中相同的这个元素。
#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() 方法中指定新元素插入的位置,并不一定就是该元素最终所处的位置。
-
向当前 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; }
-
采用如下格式的 insert() 方法,可实现一次向 set 容器中添加多个元素:
void insert ( {E1, E2,...,En} );
#include <iostream> #include <set> #include <string> using namespace std; int main() { //创建并初始化set容器 std::set<std::string> myset; //向 myset 中添加多个元素 myset.insert({ "http://c.biancheng.net/stl/", "http://c.biancheng.net/python/", "http://c.biancheng.net/java/" }); for (auto iter = myset.begin(); iter != myset.end(); ++iter) { cout << *iter << endl; } return 0; }
emplace()和emplace_hint()
emplace()
template <class... Args>
pair<iterator,bool> emplace (Args&&... args);
参数 (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;
}
emplace_hint()
template <class... Args>
iterator emplace_hint (const_iterator position, Args&&... args);
- 该方法需要额外传入一个迭代器,用来指明新元素添加到 set 容器的具体位置(新元素会添加到该迭代器指向元素的前面);
- 返回值是一个迭代器,而不再是 pair 对象。当成功添加元素时,返回的迭代器指向新添加的元素;反之,如果添加失败,则迭代器就指向 set 容器和要添加元素的值相同的元素。
#include <iostream>
#include <set>
#include <string>
using namespace std;
int main()
{
//创建并初始化 set 容器
std::set<string>myset;
//在 set 容器的指定位置添加键值对
set<string>::iterator iter = myset.emplace_hint(myset.begin(), "http://c.biancheng.net/stl/");
cout << "myset size = " << myset.size() << endl;
cout << *iter << endl;
return 0;
}
set删除数据:erase()和clear()方法
erase()
//删除 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 容器中删除元素之后的第一个元素。
#include <iostream>
#include <set>
#include <string>
using namespace std;
int main()
{
//创建并初始化 set 容器
std::set<int>myset{1,2,3,4,5};
cout << "myset size = " << myset.size() << endl;
//1) 调用第一种格式的 erase() 方法
int num = myset.erase(2); //删除元素 2,myset={1,3,4,5}
cout << "1、myset size = " << myset.size() << endl;
cout << "num = " << num << endl;
//2) 调用第二种格式的 erase() 方法
set<int>::iterator iter = myset.erase(myset.begin()); //删除元素 1,myset={3,4,5}
cout << "2、myset size = " << myset.size() << endl;
cout << "iter->" << *iter << endl;
//3) 调用第三种格式的 erase() 方法
set<int>::iterator iter2 = myset.erase(myset.begin(), --myset.end());//删除元素 3,4,myset={5}
cout << "3、myset size = " << myset.size() << endl;
cout << "iter2->" << *iter2 << endl;
return 0;
}
clear()
删除 set 容器中存储的所有元素
#include <iostream>
#include <set>
#include <string>
using namespace std;
int main()
{
//创建并初始化 set 容器
std::set<int>myset{1,2,3,4,5};
cout << "1、myset size = " << myset.size() << endl;
//清空 myset 容器
myset.clear();
cout << "2、myset size = " << myset.size() << endl;
return 0;
}
multiset容器
set 容器具有以下几个特性:
- 不再以键值对的方式存储数据,因为 set 容器专门用于存储键和值相等的键值对,因此该容器中真正存储的是各个键值对的值(value);
- set 容器在存储数据时,会根据各元素值的大小对存储的元素进行排序(默认做升序排序);
- 存储到 set 容器中的元素,虽然其类型没有明确用 const 修饰,但正常情况下它们的值是无法被修改的;
- set 容器存储的元素必须互不相等。
multiset 容器遵循 set 容器的前 3 个特性,仅在第 4 条特性上有差异。和 set 容器不同的是,multiset 容器可以存储多个值相同的元素。
multiset 类模板也定义在<set>
头文件,并位于 std 命名空间中。
创建multiset容器的方法
-
调用默认构造函数,创建空的 multiset 容器
std::multiset<std::string> mymultiset;
-
在创建 multiset 容器的同时,对其进行初始化。
std::multiset<std::string> mymultiset{ "http://c.biancheng.net/java/", "http://c.biancheng.net/stl/", "http://c.biancheng.net/python/" };
-
在创建新 multiset 容器的同时,将已有 multiset 容器中存储的所有元素全部复制到新 multiset 容器中。
std::multiset<std::string> copymultiset(mymultiset); //等同于 //std::multiset<std::string> copymultiset = mymultiset;
创建新 multiset 容器的同时,利用临时的 multiset 容器为其初始化。
multiset<string> retMultiset() { std::multiset<std::string> tempmultiset{ "http://c.biancheng.net/java/", "http://c.biancheng.net/stl/", "http://c.biancheng.net/python/" }; return tempmultiset; } std::multiset<std::string> copymultiset(retMultiset()); //等同于 //std::multiset<std::string> copymultiset = retMultiset();
由于 retMultiset() 函数的返回值是一个临时 multiset 容器,因此在初始化 copymultiset 容器时,其内部调用的是 multiset 类模板中的移动构造函数,而非拷贝构造函数。
-
取已有 multiset 容器中的部分元素,来初始化新 multiset 容器。
std::multiset<std::string> mymultiset{ "http://c.biancheng.net/java/", "http://c.biancheng.net/stl/", "http://c.biancheng.net/python/" }; std::set<std::string> copymultiset(++mymultiset.begin(), mymultiset.end());
-
手动修改 multiset 容器中的排序规则。
std::multiset<std::string, std::greater<string> > mymultiset{ "http://c.biancheng.net/java/", "http://c.biancheng.net/stl/", "http://c.biancheng.net/python/" };
multiset容器的成员方法
成员方法 | 功能 |
---|---|
begin() | 返回指向容器中第一个(注意,是已排好序的第一个)元素的双向迭代器。如果 multiset 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
end() | 返回指向容器最后一个元素(注意,是已排好序的最后一个)所在位置后一个位置的双向迭代器,通常和 begin() 结合使用。如果 multiset 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
rbegin() | 返回指向最后一个(注意,是已排好序的最后一个)元素的反向双向迭代器。如果 multiset 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。 |
rend() | 返回指向第一个(注意,是已排好序的第一个)元素所在位置前一个位置的反向双向迭代器。如果 multiset 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。 |
cbegin() | 和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。 |
cend() | 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。 |
crbegin() | 和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。 |
crend() | 和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值 |
find(val) | 在 multiset 容器中查找值为 val 的元素,如果成功找到,则返回指向该元素的双向迭代器;反之,则返回和 end() 方法一样的迭代器。另外,如果 multiset 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
lower_bound(val) | 返回一个指向当前 multiset 容器中第一个大于或等于 val 的元素的双向迭代器。如果 multiset 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
upper_bound(val) | 返回一个指向当前 multiset 容器中第一个大于 val 的元素的迭代器。如果 multiset 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
equal_range(val) | 该方法返回一个 pair 对象(包含 2 个双向迭代器),其中 pair.first 和 lower_bound() 方法的返回值等价,pair.second 和 upper_bound() 方法的返回值等价。也就是说,该方法将返回一个范围,该范围中包含所有值为 val 的元素。 |
empty() | 若容器为空,则返回 true;否则 false。 |
size() | 返回当前 multiset 容器中存有元素的个数。 |
max_size() | 返回 multiset 容器所能容纳元素的最大个数,不同的操作系统,其返回值亦不相同。 |
insert() | 向 multiset 容器中插入元素。 |
erase() | 删除 multiset 容器中存储的指定元素。 |
swap() | 交换 2 个 multiset 容器中存储的所有元素。这意味着,操作的 2 个 multiset 容器的类型必须相同。 |
clear() | 清空 multiset 容器中所有的元素,即令 multiset 容器的 size() 为 0。 |
emplace() | 在当前 multiset 容器中的指定位置直接构造新元素。其效果和 insert() 一样,但效率更高。 |
emplace_hint() | 本质上和 emplace() 在 multiset 容器中构造新元素的方式是一样的,不同之处在于,使用者必须为该方法提供一个指示新元素生成位置的迭代器,并作为该方法的第一个参数。 |
count(val) | 在当前 multiset 容器中,查找值为 val 的元素的个数,并返回。 |
由于 multiset 容器允许存储多个值相同的元素,因此诸如 count()、find()、lower_bound()、upper_bound()、equal_range()等方法,更常用于 multiset 容器。
#include <iostream>
#include <set>
#include <string>
using namespace std;
int main() {
std::multiset<int> mymultiset{1,2,2,2,3,4,5};
cout << "multiset size = " << mymultiset.size() << endl;
cout << "multiset count(2) =" << mymultiset.count(2) << endl;
//向容器中添加元素 8
mymultiset.insert(8);
//删除容器中所有值为 2 的元素
int num = mymultiset.erase(2);
cout << "删除了 " << num << " 个元素 2" << endl;
//输出容器中存储的所有元素
for (auto iter = mymultiset.begin(); iter != mymultiset.end(); ++iter) {
cout << *iter << " ";
}
return 0;
}