单独说一下Set是因为这个工具以前很少用,因为接触不多,后来发现功能太强大了,本来很多题目用Set可以快速通过,但无奈之前都没有使用set的习惯,导致吃了不少亏,set功能非常强大,原因在于Set就是一棵二叉搜索树,我们在很多题目中经常遇到需要动态储存数据,而且储存的数据在后面又需要查找使用,或者删除一些不需要的数据,而在数据结构中我们知道二叉搜索树就是这个很完美的工具,二叉搜索树查询时间为NlogN,而且查找目标元素后删除的时间复杂度为O(1),实在是很方便,而set恰好就是一个方便小巧的二叉搜索树,不过set不同的是,插入到set容器中的重复元素会被删除,也就是set中的每个元素都是独一的。
现在简单说一些set的基本用法,主要针对解题需要。
set的创建和插入
set<int>q;
q.insert(1);
q.insert(2);
set的遍历
set<int>::iterator it;
it=q.begin();
while(it!=q.end())
{
cout<<*it<<endl;
it++;
}
运行结果
需要说明,不同于vector,vector是动态数组,通过下标直接访问,这也导致了如果删除某个元素,比如vector的长度为n,删除的元素位置为x,那么后面的元素就得不断依次替换到前面的位置,导致这样的时间复杂度为n-x。而set是链表,访问只能通过指针,但是因为其二叉搜索树的性质,我们是直接通过你希望查找的元素直接进行二叉搜索树进行答案搜索,效率是非常高的,找到答案再删除就是直接修改指针,时间复杂度为O(1),非常方便。
set的搜索
以搜索的元素为目标:
返回set中大于等于x的第一个元素:
set<int>::iterator it;
cout<<"输入搜索元素:\n" ;
int x;
while(cin>>x)
{
it=q.lower_bound(x);
cout<<"搜索结果:"<<*it<<endl;
}
运行结果:
返回set中第一个大于x的元素
set<int>::iterator it;
cout<<"输入搜索元素:\n" ;
int x;
while(cin>>x)
{
it=q.upper_bound(x);
cout<<"搜索结果:"<<*it<<endl;
}
运行结果:
因为我们知道,在set中第一个大于x的元素的前面一个元素一定是小于或者等于x的,所以利用指针,我们得到:
返回set中第一个小于等于x的元素
set<int>::iterator it;
cout<<"输入搜索元素:\n" ;
int x;
while(cin>>x)
{
it=--q.upper_bound(x);
cout<<"搜索结果:"<<*it<<endl;
}
运行结果:
同理set中第一个大于等于x的元素的前一个元素一定小于x。
返回set中第一个小于x的元素
set<int>::iterator it;
cout<<"输入搜索元素:\n" ;
int x;
while(cin>>x)
{
it=--q.lower_bound(x);
cout<<"搜索结果:"<<*it<<endl;
}
运行结果:
当然不可能我们每次需要找到的元素都能在set中找到,当set无法找到满足我们需要的元素时,会返回末尾指针,记住是末尾指针,不论什么情况都是只返回末尾指针,因此可以这样判断是否目标元素被找到:
set<int>::iterator it;
cout<<"输入搜索元素:\n" ;
int x;
while(cin>>x)
{
it=--q.lower_bound(x);
if(it==q.end())//判断是否找到满足条件的元素
cout<<"搜索结果:NO\n";
else
cout<<"搜索结果:"<<*it<<endl;
}
运行结果:
元素的删除
以指针为目标删除,这个删除方式同其他容器都一样,不过set删除的是你希望删除的元素,比如删除元素x
set<int>::iterator it;
int x;
cout<<"输入删除的元素:\n";
while(cin>>x)
{
q.erase(x);//删除容器中的元素x
cout<<"剩余元素:";
it=q.begin();
while(it!=q.end())
{
cout<<*it<<" ";
it++;
}
cout<<endl;
}
运行结果:
可以看到希望删除的元素都被删除,而当删除元素-10时,容器中没有该元素,因而没有做任何改动。
查看容器中的元素个数
cout<<q.size()<<endl;