金陵酒肆留别 李白
风吹柳花满店香,吴姬压酒劝客尝。
金陵子弟来相送,欲行不行各尽觞。
请君试问东流水,别意与之谁短长。
set容器的特点
- 是一种关联式容器,底层结构用二叉树。
- 有序性:所有的元素插入时会被自动排序。
- 唯一性:每个元素的值都是唯一的,不允许插入重复的值。
- multiset可以有重复的值。
set容器的构造函数和赋值操作
| 构造函数 | 解释 |
|---|
| set() | 默认构造函数 |
| set({elem1,elem2…}) | 初始化列表构造函数 |
| set(const set st2) | 拷贝构造函数 |
| set(begin, end) | 迭代器范围构造函数 |
| set<T,自定义比较函数的对象>() | 带比较器的构造函数 |
| =赋值 | =运算符重载 |
code:
#include <iostream>
#include <vector>
#include <set>
using namespace std;
template<typename T>
void print_set(const set<T>& st)
{
for (typename set<T>::const_iterator it = st.begin(); it != st.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
template<typename T1, typename T2>
void print_set(const set<T1, T2>& st)
{
for (typename set<T1, T2>::const_iterator it = st.begin(); it != st.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
class MyCompare
{
public:
bool operator()(int v1, int v2) const
{
return v1 > v2;
}
};
void test01()
{
set<int> st1{23, 1, 56, 78, 44, 35, 99, 76};
cout << "---------- st, st.size() ---------- " << st1.size() << endl;
print_set(st1);
set<int> st2;
st2.insert(10);
st2.insert(20);
st2.insert(30);
print_set(st2);
set<int> st3(st2);
print_set(st3);
vector<int> v1{1, 2, 3, 4, 5, 6};
set<int> st4(v1.begin(), v1.end()-2);
print_set(st4);
set<int, MyCompare> st5{23, 1, 56, 78, 44, 35, 99, 76};
print_set<int, MyCompare>(st5);
set<int, MyCompare> st6 = st5;
print_set(st6);
}
int main()
{
test01();
system("pause");
return 0;
}
result:
---------- st, st.size() ---------- 8
1 23 35 44 56 76 78 99
10 20 30
10 20 30
1 2 3 4
99 78 76 56 44 35 23 1
99 78 76 56 44 35 23 1
set容器的常用接口
set容器插入元素
- set容器并没有push操作,因为set会自动排序,而push一般是增加元素在末尾位置,并不和逻辑。
- set插入元素用insert接口。
| 接口函数 | 说明 |
|---|
| pair<iterator,bool> insert (const value_type& val) | 普通引用方式传参 |
| pair<iterator,bool> insert (value_type&& val) | 右值引用方式传参 |
| iterator insert (const_iterator position, const value_type& val) | 普通引用方式传参 |
| iterator insert (const_iterator position, value_type&& val) | 以右值引用的方式传递 val 值 |
| void insert (InputIterator first, InputIterator last) | 迭代器范围传参 |
| void insert (initializer_list<value_type> il); | 初始化列表方式传参 |
普通引用方式传参和有值引用方式传参即()中的参数是一个立即释放的变量还是被定义过的变量。如int a, 如果a作为参数是普通引用方式传参,如果数值10作为参数,则为有值引用方式传参,因为实际中10只能用作右值,当前语句执行完,10就的内存就被释放。
对于set来说,插入的元素会被自动排序,那么insert接口中的pos参数是什么意思呢?它显然不是表示插入位置的。
pos不指定要插入的位置,它仅指向要开始搜索操作以插入的位置,以加快处理速度。
code:
#include <iostream>
#include <vector>
#include <set>
using namespace std;
template<typename T>
void print_set(const set<T>& st)
{
for (typename set<T>::const_iterator it = st.begin(); it != st.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
set<int> st1{23, 1, 56, 78, 44, 35, 99, 76};
cout << "---------- st, st.size() ---------- " << st1.size() << endl;
print_set(st1);
int a = 100;
pair<set<int>::iterator, bool> pr1 =st1.insert(a);
print_set(st1);
cout << "---------- pair<set<int>::iterator, bool> pr1 =st1.insert(a) ----------" << endl;
cout << "* pr1.first: " << *pr1.first << ", pr1.second: " << pr1.second << endl;
pair<set<int>::iterator, bool> pr2 = st1.insert(66);
print_set(st1);
cout << "---------- pair<set<int>::iterator, bool> pr2 = st1.insert(66) ----------" << endl;
cout << "* pr2.first: " << *pr2.first << ", pr2.second: " << pr2.second << endl;
set<int>::iterator it1 = st1.insert(st1.begin(), 88);
print_set(st1);
cout << "---------- set<int>::iterator it1 = st1.insert(st1.begin(), 88) ----------" << endl;
cout << "* it1: " << *it1 << endl;
set<int>::iterator it2 = st1.insert(st1.find(99), a);
print_set(st1);
cout << "---------- set<int>::iterator it2 = st1.insert(st1.find(99), a) ----------" << endl;
cout << "* it2: " << *it2 << endl;
vector<int> v1{11, 22, 55, 33, 99, 44};
st1.insert(v1.begin(), v1.end());
cout << "---------- st1.insert(v1.begin(), v1.end()) ----------" << endl;
print_set(st1);
set<int> st3{111, 222, 333};
st3.insert({ 888, 555, 666 });
cout << "---------- st3.insert({ 888, 555, 666 }) ----------" << endl;
print_set(st3);
}
int main()
{
test01();
system("pause");
return 0;
}
result:
---------- st, st.size() ---------- 8
1 23 35 44 56 76 78 99
1 23 35 44 56 76 78 99 100
---------- pair<set<int>::iterator, bool> pr1 =st1.insert(a) ----------
* pr1.first: 100, pr1.second: 1
1 23 35 44 56 66 76 78 99 100
---------- pair<set<int>::iterator, bool> pr2 = st1.insert(66) ----------
* pr2.first: 66, pr2.second: 1
1 23 35 44 56 66 76 78 88 99 100
---------- set<int>::iterator it1 = st1.insert(st1.begin(), 88) ----------
* it1: 88
1 23 35 44 56 66 76 78 88 99 100
---------- set<int>::iterator it2 = st1.insert(st1.find(99), a) ----------
* it2: 100
---------- st1.insert(v1.begin(), v1.end()) ----------
1 11 22 23 33 35 44 55 56 66 76 78 88 99 100
---------- st3.insert({ 888, 555, 666 }) ----------
111 222 333 555 666 888
set容器删除元素
| 接口函数 | 说明 |
|---|
| size_type erase (const value_type& val) | 删除 set 容器中值为 val 的元素,返回删除的个数,对于set来说,值为0或者1,0表示原set表示原set中无此元素 |
| iterator erase (const_iterator position) | 删除 position 迭代器指向的元素 |
| iterator erase (const_iterator first, const_iterator last) | 删除 [first,last) 区间内的所有元素 |
code:
#include <iostream>
#include <vector>
#include <set>
using namespace std;
template<typename T>
void print_set(const set<T>& st)
{
for (typename set<T>::const_iterator it = st.begin(); it != st.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
set<int> st1{23, 1, 56, 78, 44, 35, 99, 76};
cout << "---------- st1, st1.size() ---------- " << st1.size() << endl;
print_set(st1);
int size_56 = st1.erase(56);
int size_100 = st1.erase(100);
cout << "---------- st1.erase(56) ----------" << size_56 << endl;
cout << "---------- st1.erase(100) ----------" << size_100 << endl;
set<int>::iterator it = st1.erase(st1.find(23));
cout << "---------- set<int>::iterator it = st1.erase(st1.find(23)) ----------" << endl;
print_set(st1);
cout << "* it: " << *it << endl;
set<int> st2{11, 22, 33, 44, 55, 66};
cout << "---------- st2, st2.size() ---------- " << st2.size() << endl;
print_set(st2);
it = st2.erase(st2.begin(), st2.find(44));
cout << "---------- it = st2.erase(st2.begin(), st2.find(44)) ----------" << endl;
print_set(st2);
cout << "* it: " << *it << endl;
st2.clear();
cout << "---------- st2.clear(), st2.size(): ---------- " << st2.size() << endl;
print_set(st2);
}
int main()
{
test01();
system("pause");
return 0;
}
result:
---------- st1, st1.size() ---------- 8
1 23 35 44 56 76 78 99
---------- st1.erase(56) ----------1
---------- st1.erase(100) ----------0
---------- set<int>::iterator it = st1.erase(st1.find(23)) ----------
1 35 44 76 78 99
* it: 35
---------- st2, st2.size() ---------- 6
11 22 33 44 55 66
---------- it = st2.erase(st2.begin(), st2.find(44)) ----------
44 55 66
* it: 44
---------- st2.clear(), st2.size(): ---------- 0
其它接口
| 接口函数 | 说明 |
|---|
| iterator find(const key_type& _Keyval) | 返回指向所寻找的元素的iterator,没有该元素时,返回end()迭代器 |
| size_type size() | 返回set的大小 |
| bool empty() | 判断set是否为空 |
| count(size_type count(const key_type& _Keyval)) | 返回某个元素的数目,set容器为0或者1 |
code:
#include <iostream>
#include <vector>
#include <set>
using namespace std;
template<typename T>
void print_set(const set<T>& st)
{
for (auto i_st : st)
{
cout << i_st << " ";
}
cout << endl;
}
void test01()
{
set<int> st1{23, 1, 56, 78, 44, 35, 99, 76};
cout << "---------- st1, st1.size() ---------- " << st1.size() << endl;
print_set(st1);
set<int>::iterator it;
it = st1.find(22);
if (it == st1.end())
{
cout << "st1.find(22), 找不到该元素" << endl;
}
else
{
cout << "* it: " << *it << endl;
}
it = st1.find(99);
if (it == st1.end())
{
cout << "st1.find(99), 找不到该元素" << endl;
}
else
{
cout << "st1.find(99), * it: " << *it << endl;
}
cout << "st1.count(78): " << st1.count(78) << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
result:
---------- st1, st1.size() ---------- 8
1 23 35 44 56 76 78 99
st1.find(22), 找不到该元素
st1.find(99), * it: 99
st1.count(78): 1
set和multiset的区别
元素的唯一性
- set中的元素是唯一的,不允许有重复值。
- multiset可以包含重复的元素。
插入操作
- set如果插入已存在的元素,不会插入成功,容器的大小不会改变。
- multiset可以多次插入相同的值,容器的大小会改变。
查找操作
- set中要么找不到,要么只能找到一个。
- multiset查找中可能会找到多个相同值的位置。
性能影响
- set要保证元素的唯一性,在插入元素时可能需要进行多次的比较和调整操作,插入操作可能相对较慢。
- multiset在插入重复元素时相对更高效一些,但在查找特定值时可能需要检查多个相同值的位置,影响查找性能。