【STL编程】【竞赛常用】【part 2】

【STL编程】【竞赛常用】【part 1】

【STL编程】【竞赛常用】【part 1】

【STL编程】【竞赛常用】【part 2】

6. pair 容器

定义解释
pair<T1, T2> p1;创建一个空的pair对象,它的两个元素分别是T1和T2类型,采用值初始化
pair<T1, T2>p1(v1,v2):创建一个pair对象,其中first成员初始化为v1,而second成员初始化为v2
make_pair(v1.v2)以v1和v2值创建一个新的pair对象,其元素类型分别是v1和v2的类型
p1<p2两个 pair 对象之间的小于运算,其定义遵循字典次序:如果p1.first<p2.first 或者!(p2.first<p1.first)&&(p1.second<p2. second),则返回true
p1==p2如果两个pair 对象的firstsecond成员依次相等,则这两个对象相等
p.first返回p中名为first的(公有)数据成员
p.second返回p的名为second的(公有)数据成员
#include <bits/stdc++.h>
using namespace std;

int main(){
    pair<int, double> p1; //使用默认构造函数
    p1.first = 10;
    p1.second = 12.5;
    cout << p1.first << ' ' << p1.second << endl;
    return 0;
}
/*
10 12.5
*/
#include <bits/stdc++.h>
using namespace std;
typedef pair<string, double> psd; // typedef简化pair的声明为Record

int main(){
    psd p1 = make_pair("yjr", 100);
    psd p2;
    p2 = p1; //重载运算符"="
    cout << p2.first << ' ' << p2.second << endl;
    return 0;
}
/*
yjr 100
*/

pair 的比较是按照字典序比较的,比较时先按照first 的大小比较,如果相等,再按second 的大小比较:

// pair 的比较
#include <bits/stdc++.h>
using namespace std;

int main(){
    pair<int, char> A(10, 'z');
    pair<int, char> B(90, 'a');
    if (A == B)
        cout << "相等\n";
    if (A != B)
        cout << "不相等\n";
    if (A < B)
        cout << "A<B\n";
    if (A > B)
        cout << "A>B\n";
    if (A <= B)
        cout << "A<=B\n";
    if (A >= B)
        cout << "A>=B\n";
    return 0;
}
/*
不相等
A<B
A<=B
*/

7. set 集合容器

set集合容器在头文件<set>中声明,使用类似于树的结构(基于红黑树的平衡二叉检索树),存储数据并自动将数据(无重复值)由小到大排列。构造set集合容器的主要目的是快速检索(时间复杂度为O(logN)),检索效率高于vector、deque及list等容器。
在这里插入图片描述
访问set集合容器中的元素,需要通过迭代器进行。迭代器类似于指针,可以通过它指向容器中的某个元素的地址。例如set<int>::iterator ii;定义了一个set<int>类型的迭代器为ii

方法解释
s.begin()返回set容器的第一个元素
s.end()返回set容器的最后一个元素
s.clear()删除set容器中的所有的元素
s.empty()判断set容器是否为空
s.insert()插入一个元素
s.erase()删除一个元素
s.size()返回当前set容器中的元素个数
s.lower_bound()返回第一个大于或等于给定关键值的元素
s.upper_bound()返回第一个大于给定关键值的元素
s.equal_range()返回一对定位器,分别表示 第一个大于或等于给定关键值的元素 和 第一个大于给定关键值的元素,这个返回值是一个pair类型,如果这一对定位器中哪个返回失败,就会等于 s.end()
#include <bits/stdc++.h>
using namespace std;

int main(){
    set<int> s;
    for (int i = 10; i > 0; --i) //此处由大到小赋值
        s.insert(i);             //插入元素
    set<int> s2(s);              //拷贝s生成s2
    s.erase(s.begin());          //删除操作
    s.erase(6);
    s.insert(5);                              //不会重复插入
    set<int>::iterator ii;                    // ii为前向迭代器
    for (ii = s.begin(); ii != s.end(); ii++) //遍历
        cout << *ii << ' ';
    cout << "\n元素个数为" << s.size(); //统计set中元素个数,时间复杂度O(1)
    ii = s.find(10);                    //查找元素值,并返回指向该元素的迭代器
    if (ii != s.end())                  //如容器中不存在该元素,返回值等于s.end()
        cout << "\n查找=" << *ii;
    if (s.count(5)) //返回set中值为5的元素个数,时间复杂度为O(log n)
        cout << "\n存在元素5";
    s.clear(); //清空所有元素
    cout << "\n元素是否为空:" << s.empty();
    return 0;
}

/*
		2 3 4 5 7 8 9 10
		元素个数为8
		查找=10
		存在元素5
		元素是否为空:1
*/
#include<bits/stdc++.h>
using namespace std;

int main(){
    set<int> myset;
    for (int i = 1; i < 11; i++){
		myset.insert(i);
	}
	cout << "lower_bound & upper_bound test:" << endl;
	cout << "第一个大于等于3的元素:" << *myset.lower_bound(3) << endl; //函数实际返回地址值
	cout << "第一个大于3的元素:" << *myset.upper_bound(3) << endl;	
	cout << "equal_range test:" << endl;
	cout << "第一个大于或等于2的元素: " << *myset.equal_range(2).first << endl;
	cout << "第一个大于2的元素: " << *myset.equal_range(2).second << endl;
	if (myset.equal_range(20).first == myset.end())
		cout << "不存在大于等于20的元素" << endl;
	myset.clear();
    return 0;
}
/* 
		第一个大于等于3的元素:3
		第一个大于3的元素:4
		equal_range test:
		第一个大于或等于2的元素: 2
		第一个大于2的元素: 3
		不存在大于等于20的元素
 */

使用insert()将元素插入set集合容器的时候,集合容器默认按由小到大的顺序插入元素,然而在很多情况下(例如需要由大到小排序)需要自行编写比较函数。

// set的比较函数
#include <bits/stdc++.h>
using namespace std;

struct Comp{
    bool operator()(const int &a, const int &b){
        return a > b; //从大到小排序
        // return a < b;  //从小到大排序
    }
}; //需在结构体内定义比较函数

int main(){
    set<int, Comp> s;             // set调用的比较函数为Comp
    for (int i = 1; i <= 10; ++i) //此处是由小到到赋值
        s.insert(i);
    set<int>::iterator ii;
    for (ii = s.begin(); ii != s.end(); ii++) //遍历
        cout << *ii << ' ';
    return 0;
}
/*
		10 9 8 7 6 5 4 3 2 1 
*/

重载操作符可以使得自定义类型像基本数据类型一样支持加、减、乘、除、自加、自减等各种操作。operator是C++的关键字,它和操作符(例如“ () ”)一起使用,表示运算符重载函数,在理解时可将operator和运算符(例如“operator()”)视为函数名。

参数定义为const int &aconst int &b这种形式,一是防止a和b被修改,二是通过引用变量的方式减少系统开销。末尾的const也是为了防止被修改。

实际上,很多C++操作符已经被重载了,例如 “*” 用于两个数字之间时,得到的是它们的乘积;用于一个地址之前时,得到的是这个地址上存储的值。cin>>x和cout<<x中的“>>”和“<<”运算符也被重载了。

例如自定义一个结构体Time类型,并想实现两个Time类型相加的操作(即小时与小时相加,分钟与分钟相加,秒与秒相加),其程序可能如下所示。

#include <bits/stdc++.h>
using namespace std;

struct Time{
    int H, M, S;                        //时,分,秒
    Time operator+(const Time &b) const //重载运算符"+"
    {
        return Time{H + b.H, M + b.M, S + b.S}; //仅为演示,不考虑进位
    }
} T1 = {3, 2, 4}, T2 = {5, 20, 30}, T3;

int main(){
    T3 = T1 + T2;
    cout << T3.H << ":" << T3.M << ":" << T3.S << endl;
    return 0;
}
/*
		8:22:34
*/

C++只能重载已有的操作符。下表列出了可以被重载的操作符。

在这里插入图片描述
当元素是结构体时,必须要重载运算符“<”:

// set的结构体排序
#include <bits/stdc++.h>
using namespace std;

struct Info{
    string name;
    double score;
    bool operator<(const Info &a) const  {//重载"<"操作符,照抄即可
        return a.score < score; //从大到小排序
     // return a.score >score;  //从小到大排序
    }
} info;

int main(){
    set<Info> s;
    info = {"A", 90.0};
    s.insert(info);
    info = {"B", 92.0};
    s.insert(info);
    info = {"C", 96.0};
    s.insert(info);

    set<Info>::iterator ii;
    for (ii = s.begin(); ii != s.end(); ii++) //遍历
        cout << (*ii).name << ' ' << (*ii).score << endl;
    return 0;
}
/*
		C 96
		B 92
		A 90
*/

8. multiset 多重集合容器

multiset多重集合容器在头文件<set>中定义,它可以看成序列,序列中可以存在重复的数。multiset能时刻保证序列中的数是有序的(默认从小到大排序),插入一个数或删除一个数都能够在O(logn)的时间内完成。

#include <bits/stdc++.h>
using namespace std;

int main(){
    multiset<int> m;
    m.insert(11); //插入数据
    m.insert(21);
    m.insert(10);
    m.insert(12);
    m.insert(12);
    m.insert(11);
    m.insert(11);
    m.insert(11);
    m.insert(9);
    cout << "11的个数有" << m.count(11) << endl; //输出multiset中11的个数
    cout << "第一个大于等于10的元素为:" << *m.lower_bound(10) << endl;
    cout << "第一个大于11的元素为:" << *m.upper_bound(11) << endl;
    multiset<int>::iterator it;
    for (it = m.begin(); it != m.end(); it++)
        cout << *it << endl;                            //从小到大输出
    cout << "删除12,有" << m.erase(12) << "个" << endl; //删除等于12的元素
    cout << "查找9\n";
    multiset<int>::iterator i = m.find(9); //查找v,返回该元素的迭代器位置
    if (i != m.end())                      //找到则输出,否则i为end()迭代器位置
        cout << *i << endl;
    pair<multiset<int>::iterator, multiset<int>::iterator> p;
    int v = 11;
    // equal_range:有序容器中表示一个值第一次出现与最后一次出现的后一位
    p = m.equal_range(v); //查找所有相同元素
    cout << "大于等于" << v << "的第一个元素为" << *p.first << endl;
    cout << "大于" << v << "的第一个元素为" << *p.second << endl;
    cout << "键值为" << v << "的全部元素为";
    for (it = p.first; it != p.second; it++) //打印重复键值元素11
        cout << *it << " ";
    m.clear(); //清空所有元素
    return 0;
}

11的个数有4
第一个大于等于10的元素为:10
第一个大于11的元素为:12     
9
10
11
11
11
11
12
12
21
删除12,2个
查找9
9
大于等于11的第一个元素为11
大于11的第一个元素为21
键值为11的全部元素为11 11 11 11

9. map 映射容器

map映照容器在头文件<map>中定义,它的元素数据是由键值和映照数据组成的,键值与映照数据之间具有一一对应的关系。
在这里插入图片描述
map映照容器和set集合容器一样都是采用红黑树来实现的,插入键值的元素不允许重复,元素默认是按键值由小到大排序的。如果定义比较函数,比较函数也只能对元素的键值进行比较,元素的各项数据可通过键值检索出来。
mapset的区别是:map是处理带有键值的记录型元素数据的快速插入、删除及检索,而set是对单一数据的处理。

方法解释
begin()返回指向map头部的迭代器
end()返回指向map末尾的迭代器
rbegin()返回一个指向map尾部的逆向迭代器
rend()返回一个指向map头部的逆向迭代器
clear()删除所有元素
count()返回指定元素出现的次数(因为key值不会重复,所以只能是1 or 0)
empty()如果map为空则返回true
equal_range()返回特殊条目的迭代器对
erase()删除一个元素
find()查找一个元素
insert()插入元素
size()返回map中元素的个数
swap()交换两个map
get_allocator()返回map的配置器
key_comp()返回比较元素key的函数
value_comp()返回比较元素value的函数
lower_bound()返回键值>=给定元素的第一个位置
upper_bound()返回键值>给定元素的第一个位置
max_size()返回可以容纳的最大元素个数
size()返回map中元素的个数
swap()交换两个map
#include <bits/stdc++.h>
using namespace std;

int main(){
    map<int, string> ms;
    ms[1] = "student_one";
    ms[1] = "student_two"; // id相同,则覆盖
    ms[2] = "student_three";
    map<int, string>::iterator iter;
    ms.insert(make_pair(3, "student_four")); //插入新元素
    for (iter = ms.begin(); iter != ms.end(); iter++)
        cout << iter->first << " " << iter->second << endl;
    cout << endl;
    iter = ms.lower_bound(1); //首个大于等于1的元素
    cout << iter->second << endl;
    iter = ms.upper_bound(1); //首个大于1的元素
    cout << iter->second << endl;
    iter = ms.find(1); //查找键值为1的元素位置
    ms.erase(iter);    //删除键值为1的元素
    for (iter = ms.begin(); iter != ms.end(); iter++)
        cout << iter->first << " " << iter->second << endl;
    ms.erase(ms.begin(), ms.end()); //删除全部元素
    cout <<"size: "<< ms.size() << endl;
    cout <<"empty: "<< ms.empty() << endl;// empty()判断map是否为空
    return 0;
}

结果:

1 student_two
2 student_three
3 student_four

student_two
student_three
2 student_three
3 student_four
size: 0
empty: 1
#include <bits/stdc++.h>
using namespace std;

struct Info{ //学生信息结构体
    char *xm; //姓名
    int y;    //年份
    char *d;  //地址
};

struct Record {//学生记录结构体
    int id;  //学号作键值
    Info sf; //学生信息作映照数据
};

int main(){
    Record srArray[] ={
            {4, "Li", 21, "beijing"},
            {2, "wang", 29, "shanghai"},
            {3, "zhang", 30, "shengzheng"}};
    map<int, Info, greater<int>> m; //按键值由大到小排序
    for (int j = 0; j < 3; j++)     //装入三个学生信息
        m[srArray[j].id] = srArray[j].sf;
    Record s1 = {5, "Ling", 23, "XINJIANG"};
    m.insert(make_pair(s1.id, s1.sf)); //插入新生信息
    map<int, Info>::iterator i;
    for (i = m.begin(); i != m.end(); i++) //正向遍历
        cout << (*i).first << ' ' << (*i).second.xm << ' ' << (*i).second.d << '\n';
    i = m.find(2); //查找键值为2的记录并输出
    cout << "Key value 2: " << (*i).second.xm << ' ' << (*i).second.d;
    return 0;
}

结果:

5 Ling XINJIANG
4 Li beijing
3 zhang shengzheng
2 wang shanghai
Key value 2:wang shanghai

10. multimap 多重映射容器

multimapmap 的功能基本相同,唯独不同的是multimap 允许插入重复键值的元素,由于允许插入重复键值的元素,因此multimap 的元素插入、删除以及查找与map不同。

#include <bits/stdc++.h> //使用万能头文件,无需写#include <map>
using namespace std;

int main(){
    multimap<string, double> mp;                    //定义map对象,当前没有任何元素
    mp.insert(pair<string, double>("Jack", 300.5)); //插入元素a
    mp.insert(pair<string, double>("Kity", 200));
    mp.insert(pair<string, double>("Memi", 500));
    mp.insert(pair<string, double>("Jack", 306)); //重复插入键值"Jack"

    multimap<string, double>::iterator it;
    mp.erase("Jack");                           //删除键值等于"Jack"的元素
    for (it = mp.begin(); it != mp.end(); it++) //前向迭代器中序遍历multimap
        cout << (*it).first << " " << (*it).second << endl;

    it = mp.find("Nacy"); //元素的查找
    if (it != mp.end())   //找到
        cout << (*it).first << " " << (*it).second << endl;
    else //没找到
        cout << "Not find it!" << endl;
    return 0;
}

结果:

Kity 200
Memi 500
Not find it!

【STL编程】【竞赛常用】【part 3】

敬请期待!!!

11. list 双向链表容器

12. stack 堆栈容器

13. queue 队列容器

14. deque 双端队列容器

15. priority_queue 优先队列容器

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
C++竞赛中,常用STL(Standard Template Library)组件有vector、stack以及算法函数next_permutation。vector是一个动态数组容器,可以方便地进行元素的插入、删除和访问。stack是一个后进先出(LIFO)的容器,常用于实现递归、深度优先搜索等算法。next_permutation是一个算法函数,用于按照字典序生成某个序列的所有排列。 在竞赛中,我们可以利用vector来存储元素,使用push_back函数添加元素,使用[]操作符或迭代器进行元素的访问。可以使用stack来模拟递归过程,实现一些深度优先搜索的问题。而使用next_permutation函数可以方便地生成某个序列的所有排列。 举个例子,如果我们想要按照字典序输出1到n的全排列,可以使用next_permutation函数结合vector来实现。首先,我们可以使用一个for循环将1到n的元素添加到vector中。然后,使用do-while循环来不断调用next_permutation函数,每次生成下一个排列并输出。最后,当next_permutation函数返回false时,表示已经生成了所有的排列,循环结束。 另外,如果我们需要使用栈来解决一些问题,可以使用stack容器。可以使用push函数将元素入栈,使用pop函数将元素出栈。栈的特点是后进先出,所以可以用来模拟递归过程或实现一些需要回溯的算法。 总结起来,在C++竞赛中,常用STL组件有vector、stack和算法函数next_permutation。vector可以方便地进行元素的插入、删除和访问,stack可以模拟递归过程,而next_permutation函数可以生成某个序列的所有排列。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Eternity_GQM

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值