【原创】C++ 集合set与关联性容器

版权声明:未经过作者允许,QωQ是可以转载的,只不过要赞一下本文章并发评论告诉我,然后转载附上原网址就好了!=QωQ= https://blog.csdn.net/c20182030/article/details/70799170

关联性容器 set

引入

map和set常常用,但是不太了解,不太深入。想要深入的了解,发现网上的全是一些高级的东西,讲讲了map和set的定义,但是并没有或是很少提及用法。想看用法,但是看着冗杂,不够精简,特别是对于像我这种理解力低的渣渣,感到一脸茫然。
于是就起了自己写一篇博客的念头。

关联性容器

set和map都叫做关联性容器
什么是关联性容器呢?
我们就需要把它和另一种容器,顺序性容器合着一起讲。
它们的区别在于:

关联容器通过键存储和读取元素,顺序容器通过元素在容器中的位置顺序存储和访问元素。

也就是说,

序列式容器强调值的排序,而关联式容器则在值中选择一个值作为一个关键字,这个关键字起到对值的索引的作用,方便查找。

举个例子,穿着独一无二跑的超快鞋的小明,迟到了。
老师问:
“小明是不是又是最后一个进教室的?” 这就是顺序性容器。
“小明是不是又穿着独一无二跑的超快鞋?”这就是关联性容器。

set的定义和基本概念

来,复习高中数学必修一第一课!
(我不会告诉你我还是初二)
集合!集合!集合!
于是人们开发出了set。

set,就是集合,它主要利用了集合的互异性,也就是说,set的每个元素值唯一

set的内部自建一颗红黑树,一种二叉平衡树。而STL相当于提供了红黑树的接口函数,让程序员的使用更加方便。

set的头文件

set需要

#include<set>
using namespace std;

这两个头文件。

扫描二维码关注公众号,回复: 3196387 查看本文章

set的声明与构造函数

set声明的基本格式是:

set <数据类型> 名称 ;

比如:

set <int> s;
set <double> m;
set <char> w;

set的基本操作与遍历

set <int> s;为例。

基本操作

set的最基本的操作有下列几种:

s.begin()//返回s的迭代器
s.end()//返回s的迭代器
s.clear()//删除s中的所有的元素
s.empty()//判断s是否为空,空返回1,不空返回0
s.max_size()//返回s最多能装的元素个数
s.size()//返回s当前有多少个元素
s.find(k)//在s里找k,找到返回k的迭代器,否则返回s.end();
s.count(k)//返回s里k的个数,因为set去重,所以只会返回0或1

在以上返回迭代器的函数前加上*,就能返回该迭代器对应的值
//事实上,所有迭代器前面加上*,都是它所代表的值

set与迭代器

如果想要遍历set的话,我们需要定义一个迭代器

set <int> ::iterator iter;

因为s.begin()s.end()返回的也是迭代器,所以说我们可以这样来遍历一个set:

set <int> ::iterator iter;
for(iter=s.begin();iter!=s.end();iter++)
    cout<<*iter<<endl;//因为iter也是迭代器,要输出它所代表的值,需要加上‘*’号

如果你像输出set里第k个元素,那么只需要令iter=s.begin();然后再循环k-1iter++;,就可以了。

举个例子:

#include<cstdio>
#include<iostream>
#include<set>
using namespace std;

int a[12]={5,4,5,8,8,3,2,9,6,1,0,7};
set<int> s;

int main()
{
    for(int i=0;i<12;i++) s.insert(a[i]);
    set <int> ::iterator iter;
    for(iter=s.begin();iter!=s.end();iter++)
        cout<<*iter<<' ';
}

我们依次往set里插入5,4,5,8,8,3,2,9,6,1,0,7,来看看结果:
0 1 2 3 4 5 6 7 8 9
因此我们发现,set不仅自动去重,而且自动升序排序

set的插入和删除

插入

上文已经提到过一种,除此之外,set还支持另外一种插入

s.insert(k);

在s里插入一个关键字k,自动去重,自动排序。

s.insert(left,right);

注意:left,right是两个迭代器

插入left和right代表的一段区间。
比如说刚才的程序就可以改为:

#include<cstdio>
#include<iostream>
#include<set>
using namespace std;

int a[12]={5,4,5,8,8,3,2,9,6,1,0,7};
set<int> s;

int main()
{
    s.insert(a+0,a+12);
    set <int> ::iterator iter;
    cout<<"s.insert(a+0,a+12) : ";
    for(iter=s.begin();iter!=s.end();iter++)
        cout<<*iter<<' ';
    cout<<endl<<"s.insert(a+0,a+11) : ";
    s.clear();
    s.insert(a+0,a+11);
    for(iter=s.begin();iter!=s.end();iter++)
        cout<<*iter<<' ';
}

我们插入了两次,一次s.insert(a+0,a+12),一次s.insert(a+0,a+11)。来看看结果:

s.insert(a+0,a+12) : 0 1 2 3 4 5 6 7 8 9 
s.insert(a+0,a+11) : 0 1 2 3 4 5 6 8 9 

少了一个7!
因此我们可以知道,s.insert(left,right);插入的区间是半开半闭区间[left,right)

删除

set支持三种删除。

s.erase(k);

删除关键字为k的元素。

s.erase(iterator);

删除迭代器为iterator的元素。

s.erase(left,right);

删除区间[left,right)的元素。

注意

注意,set的删除并不会判断删除的正确性。也就是说,就算set里没有你要删的元素,set也会去删。在删除之前一定要特判

set的查找

介绍四种查找。

s.find(k);//返回k的迭代器,如果没有返回s.end();
s.count(k);//返回k的个数(在set中只有01)
s.upper_bound(k);//返回第一个大于等于k的迭代器
s.lower_bound(k);//返回最后一个大于等于k的迭代器

set的排序机制

上文提到过,set自动升序排列。这是int类,再来试试char:

#include<cstdio>
#include<iostream>
#include<set>
using namespace std;

char a[10]={'x','c','Z','P','A','l','L','k','S','S'};
set <char> s;

int main()
{
    s.insert(a+0,a+10);
    set <char> ::iterator iter;
    for(iter=s.begin();iter!=s.end();iter++)
        cout<<*iter<<" ";
}

结果:A L P S Z c k l x

在char里也会按照ASCII码大小升序排序

问题来了,我如果我想用自己的方法排序呢?

不用结构体

新建一个结构体,重载 ()

struct Comp
{
    bool operator () const (const another_struct &a , const another_struct &b)//another_struct is another strcut
    {
        //make your own rules
    }
};

要让set使用这个规则,声明时改成:set <int,Comp>;

结构体

在结构体里重载<即可。

struct node
{
    bool operator < (const & a) const
    {
        //make your own rules
    }
};

multiset

STL的另一种关联性容器,它不会去重,用法与set如出一辙。

猜你喜欢

转载自blog.csdn.net/c20182030/article/details/70799170