C++ | 集合 set
一.集合
是由若干个不相同的元素组成的,如 \(\{1,2,3\}\),可用 set
表示集合
需要加 #include<set>
支持 #include<bits/stdc++.h>
1.定义方法:
set <T> s;
set <int> aa;
set <string> bbb;
2.插入元素
insert(*****);
set <int> s;
s.insert(1);
插入相同元素时,不会做修改也不会报错
3.删除元素
set <int> s;
s.insert(1);
s.erase(1);//有 1 ,删除它
s.erase(1);//没有,不理这句话
4.判断元素是否存在
set <int> s;
s.insert(1);
if(s.count(1))//判断1存在吗?
{
cout<<"1";
}
运行结果:1
5.元素的遍历(每一个元素)
begin()
集合的开始
end()
集合的末尾
遍历代码:(输出的顺序:从小到大或字典序)
set <int> s;
for(set<int>::iterator i=s.begin();i!=s.end();i++)
{
cout<<*i<<endl;
// 迭代器
}
迭代器可以放在for
循环之外
set <int> s;
set <int>::iterator i;
for(i=s.begin();i!=s.end();i++)
{
cout<<*i<<endl;
// 迭代器
}
6.获取元素的个数
set <int> s;
int num=s.size();
7.集合的清空,同时释放内存
set <int> s;
s.clear();
8.时间复杂度
insert \(O(\log(n))\)
erase \(O(\log(n))\)
count \(O(\log(n))\)
size \(O(1)\)
clear \(O(n)\)
9.运算符重载
由于set
是自带排序的,但自定义的结构体系统不会排序
这时就需要一个像sort
中cmp
的东西,叫运算符重载
这个代码重载了小于号
struct Node
{
int x,y;
bool operator<(const Node &rhs) const //当两边都是Node类型的变量且中间是小于号时
{
//谁小谁就靠前
if(x=rhs.x) y<rhs.y;
else return x<rhs.x;
}
};
实践:用结构体和集合,输入n个点,去重输出。
#include<bits/stdc++.h>
using namespace std;
struct Point
{
int x,y;
bool operator<(const Point &rhs) const
{
if(x==rhs.x)return y<rhs.y;
else return x<rhs.x;
}
};
int main()
{
int n;//n个点
set <Point> v;
cin>>n;
for(int i=0;i<n;i++)
{
Point temp;//每一个点
cin>>temp.x>>temp.y;
v.insert(temp);//往集合里加
}
//遍历
for(set<Point>::iterator i=v.begin();i!=v.end();i++)
{
//指针
cout<<i->x<<" "<<i->y<<endl;
//等价于 *(it).x
}
return 0;
}
10.两个实用函数
见\(2.3\)
二.多重集合
也在头文件set
中。一个元素可以存多次。
1.定义、插入、计数和删除
multiset <int> ms;
ms.insert(5);//{5}
ms.insert(2);//{2,5}
ms.erase(5);//{2}
ms.erase(1);//{2}
ms.insert(6);//{2,6}
ms.insert(6);//{2,6,6}
ms.erase(6);//{2,6}
int w=ms.count(6);//6的个数,是1
2.仅删除一个
上面的erase
会把集合中所有的元素都删除,可用find
只删除一个。
find(x)
是迭代器,表示集合中第一次出现x
的位置
multiset <int> ms;
for(int i=1;i<=3;i++)ms.insert(5);//{5,5,5}
ms.erase(ms.find(5));//删除第一个元素
cout<<ms.count(5);//输出2
3.两个实用函数、删除与大小
lower_bound(x)
返回第一个大于等于x
的元素的迭代器
upper_bound(x)
返回第一个大于x
的元素的迭代器
实践:
multiset <int> ms;
ms.insert(4);
ms.insert(5);
ms.insert(5);
ms.insert(7);
cout<<*ms.lower_bound(4)<<endl;//4
cout<<*ms.upper_bound(4)<<endl;//5
cout<<*ms.lower_bound(9)<<endl;//没有,有4个元素,4
//如果要找位置,就继续用迭代器
multiset<int>::iterator i=ms.lower_bound(4);//也可以写upper_bound(4)
if(i==ms.end())cout<<"-1";//这个就是找不到,没有
cout<<*i<<endl;//具体值
ms.erase(i);//删除迭代器,不是删除 *i
cout<<ms.size();//大小,3
三.映射表
指两个集合间的关系,如姓名集合\(\{"TOM","JONE","MARY"\}\)和班级集合\(\{1,2\}\)可以有:
\(class("TOM")=1\)
\(class("JONE")=2\)
\(class("MARY")=1\)
我们称姓名集合为关键字集合\((key)\),班级集合为值集合\((value)\)
用map
来存储映射表
1.引用库
引用以下两种之一即可
#include<map>
#include<bits/stdc++.h>
2.构造映射
//map <T1,T2> m;
map <string,int> m;
// 关键字 值
3.插入映射
//接着上面的
m["TOM"]=1;//{"TOM"->1}
//也就可以输出
cout<<m["TOM"]<<endl;
//如果重复赋值将会覆盖
//赋值这样也可以:
m.insert(make_pair("TOM",1));
m["TOM"]=2;//覆盖
m["TOM"]++;//也是覆盖,+1
m["JANE"]++;//直接赋值为1
4.判断关键字是否存在
if(m.count("TOM"))cout<<1;
5.遍历(从小到大或字典序)
for(map<string,int>::iterator i=m.begin();i!=m.end();i++)
cout<<i->first<<" "<<i->second<<endl;
// 关键字 对应的值
// 也可以是 (*it).first
6.清空并释放内存
m.clear();
7.时间复杂度
insert \(O(\log(n))\)
count \(O(\log(n))\)
size \(O(1)\)
clear \(O(n)\)
三.二维map
1.map
套用set
举个例子:map<int,set<string>> s;
// 班级 姓名集合
对于2班和TOM,就可以
s[2].insert("TOM");//TOM加入2班
if(s[2].count("TOM"))cout<<1;//查询TOM是否在2班
s[2].erase("TOM");//2班踢出TOM
遍历
for(map<int,set<string> >::iterator i=m.begin();i!=m.end();i++)
{
for(set<string>::iterator i2=(i->second).begin();i2!=(i->second).end();i2++)
{
cout<<*i2<<" is in class "<<i->first<<endl;
}
}
2.map
套用map
举个例子:map<int,map<string,int>> s;
//针对重名 班级 姓名 次数
对于2班和TOM,就可以
s[2]["TOM"]++;//新来了一个叫TOM的人
cout<<s[2]["TOM"]++;//现在有多少个叫TOM的人
遍历:
for(map<int,map<string,int>>::iterator i1=s.begin();i1!=s.end;i1++)
{
for(map<string,int>::iterator i2=i1->second.begin();i2!=i1->second.end();i2++)
cout<<"There are "<<i2->second<<" people named "<<i2->first<<" in class "<<i1->first<<endl;
}
四.补充的杂七杂八 \(STL\)
1.小写转换
string s;
cin>>s;
s=tolower(word[i]);