蓝桥杯省赛备战笔记—— (七)常用STL

一、动态数组 vector

动态数组, 写作 vector 就是不定长数组,数组的长度可以根据我们的需要动态改变

引用库

c++ 中 vector 的实现在一个 <vector> 头文件中,且要使用std 命名空间,加一句 usiing namespace std;

#include<vector>
using namespace std;
......

使用

vector<T> name;
T 是类型名,可以是 int float double 或者自定义的数据类型

vector<int> a;
定义了一个 存储整数的动态数组a //初始时,a是空的

基本操作

#include<stdio.h>
#include<vector>
using namespace std;
int main(){
    vector<int> a;
    a.push_back(1);  //往最后插入一个元素 
    a.push_back(2);
    a.push_back(3);
    a.push_back(4);
    for(int i = 0; i < a.size();i++){  //获取大小 
        printf("%d ",a[i]);  //访问动态数组中的元素 
    }
    return 0;
}

修改:

a[1] = 3;   //直接赋值即可

尾部删除:

 a.pop_back();

清空: //只会清空vector,并不会清空开辟的内存

a.clear();

清空开辟的内存:

vector<int>().swap(a);    //申请一个空的vector, 与 a 交换,即可清空 a 开辟的内存

练习:利用vector存储结构体,并自定义排序

#include<vector>
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
struct Stu{
    string name;
    int age;
    Stu(string na,int ag):name(na),age(ag){
    }
};
vector<Stu> S;
bool cmp(Stu a,Stu b){
    return a.age > b.age;
}
int main(){
    int n;
    scanf("%d",&n);
    int a;
    string na;
    for(int i = 0; i < n;i++){
        cin >> na >> a;
        Stu s(na,a);
        S.push_back(s);
    }
    sort(S.begin(),S.end(),cmp);
    for(int i = 0;i < S.size();i++)
            cout << S[i].name <<  " ";return 0;
}

动态数组的初始化:

int n = 10;
vector<int> a(n,1);

第一个参数表示出事的动态数组的长度,第二个参数表示初始的数组里面每个元素的值。如果不传入第二个参数,初始值都是0

 二维动态数组

vectot<vector<int> >a

注意, <int> >中间有一个空格。这个空格必须加上,否则一些老版本的编译器将不能通过编译

练习:

#include<stdio.h>
#include<vector>
using namespace std;
vector<vector<int> >a;
const int n = 5;
int main(){
    for(int i = 0; i < n;i++){
        vector<int> b (i+1,1);
        a.push_back(b);
    }
    for(int i = 0;i < n;i++){
        for(int j = 0; j< a[i].size();j++){
            printf("%d ",a[i][j]);
        }
        printf("
");
    }
    
    return 0;
}

注意:访问 vector 必须时刻注意范围,可以提前开辟好 vector<vector<int> >a(n,vector<int>(m,0)); 如果没有初始化或者 push_back() ,要慎重访问

 

 

练习:利用 vector 打印乘法表

#include<stdio.h>
#include<vector>
using namespace std;
vector<vector<int> >a;
const int n =  9;
int main(){
    for(int i = 0; i < n;i++){
        a.push_back(vector<int>());
    }
    for(int i = 0; i < a.size();i++){
        for(int j = 0; j <= i;j++){
            a[i].push_back((i+1) * (j+1));    
        }
    }
    for(int i = 0 ; i < a.size();i++){
        for(int j = 0; j < a[i].size();j++){
            printf("%d * %d = %d ",j+1,i+1,a[i][j]);
        }
        printf("
");
    }
    return 0;
}

二、集合set

 不重复数据组成

引用库

#include<set>
using namespace std;

构造

set<T> s;
T 为数据类型,  s 为名字
初始的时候,s 是空集合
例如:
set<int> a;
set<string> b; 

插入、删除、判断是否存在

#include<iostream>
#include<string>
#include<set>
using namespace std;
set<string> country;
int main(){
    country.insert("China");   //插入
    country.insert("German");
    country.insert("Russia");
    country.insert("China");  //如果集合中已经存在了某个元素,插入时不会产生任何效果
    country.erase("German");   //删除操作————如果集合中不存在要删除的元素,不进行任何操作
    if(country.count("China")){    //查找操作————如果集合中存在要查找的元素,返回1,否则返回0
        cout << "China..." << endl;
    }
    return 0;
}

遍历元素

c++ 通过迭代器可以访问集合中的每个元素

通过 * (解引用运算符,不是乘号)可以获取迭代器指向的元素

通过 ++ 操作,让迭代器指向下一个元素, -- 操作让迭代器指向上一个元素

set<T>::iterator it 
定义了一个指向 set<T>集合的迭代器 it
T是任意的数据类型
::iterator 是固定的写法

begin 函数返回容器中起始元素的迭代器。end 函数返回容器的尾后迭代器

其中,end 函数的那一位其实是集合最后位的下一位,实际是空的

如果要取最后一位元素的话,记得 end--

#include<iostream>
#include<string>
#include<set>
using namespace std;
set<string> country;
int main(){
    country.insert("China");   
    country.insert("German");
    country.insert("Russia");
    country.insert("America");  
    for(set<string>::iterator it = country.begin(); it != country.end();it++){
        cout << *it<<endl;
    }
    
    return 0;
}

c++ 中遍历 set 是从小到大遍历的。也就是set 会自动帮我们排序 —————— 如果set中放置的是自定义的结构体的话,还需要重载 ’ < ‘ 运算符

 【set 是红黑树的结构】

清空

a.clear()      //清空set,同时会清空内存

set和结构体

 set内部是从小到大排序的,对于自定义的结构体,需要运算符重载,重新定义小于符号

struct Node{
    int x,y;
    bool operator < (const Node &rhs) const{
        if(x == rhs.x){
            return y < rhs.y;
        }else{
            return x < rhs.x;
        }
    }
};

练习:

#include<stdio.h>
#include<set>
using namespace std;
struct Point{
    int x,y;
    bool operator < (const Point &a) const{
        if(x == a.x){
            return y < a.y;
        }else{
            return x < a.x;
        }
    }
};
int main(){
    int n;
    scanf("%d",&n);
    Point p;
    set<Point> v;
    for(int i = 0; i< n;i++){
        int x,y;
        scanf("%d %d",&x,&y);
        p.x = x;
        p.y = y;
        v.insert(p);
    }
    
    for(set<Point>::iterator it = v.begin(); it != v.end();it++){
        printf("%d %d
",it -> x,it -> y);
    }
    return 0;
}

三、映射map

 引用库

#include<map>
using namespace std;

构造一个映射

map<T1,T2> m;
定义了一个名为m 的从T1 类型到 T2类型的映射。初始的时候,m是空映射
例如:
map<string,int> m;

插入一个新的映射

 

 映射访问

 

映射是否存在

某个关键字是否被映射过,你可以直接用 count() 函数。如果关键字存在,返回1,否则会返回0。

 遍历映射

C++通过迭代器可以访问集合中的每个元素。这里迭代器指向的元素是一个pair,有first和second两个成员变量,分别代
表一个映射的key和value。
我们用  ->  运算符来获取值,it->first 和   (*it). first   的效果是一样的,就是获取迭代器it指向的pair里first成员的值。

遍历map是按照关键字从小到大遍历的

 清空

clear()  函数,可以清空map及其占用的内存

#include<iostream>
#include<map>
#include<string>
#include<utility>
using namespace std;
int main(){
    map<string,int> dict;              //dict 是一个string 到 int 的映射,存放每个名字对应的班级号,初始为空
    dict.insert(make_pair("Tom",1));
    dict.insert(make_pair("Jone",2));
    dict["Jike"] = 2;
    dict["Mary"] = 2;
    dict["Tom"] = 1;
    if(dict.count("Mary")){  //如果存在 
        cout << "Marry is in class" << dict["Mary"] << endl;  //访问 
    }      
    for(map<string,int>::iterator it = dict.begin(); it != dict.end();it++){   //迭代器 
        cout << it->first << "->" << it->second <<endl;   //first 是关键字,second 是对应的值 
    }
    dict.clear();  //如果不继续赋值,实际上没必要清空内存 
    return 0;
}

map套用set
为了帮助理解,我们举用一个生活中实际例子。全校有很多班级,每个班级每个人都会有中文名。现在我们需要用一种方式来
记录全校的同学的名字。如果直接用一个set记录,对于重名的同学,那么就没办法分辨了。
我们可以把全校的班级进行编号,对每一个班级建立一 个set,也就是每个班级都映射成一个set,这样就能分辨不同班级的
同名同学了。对于同班的同学来说,一般很少有 重名的。

 map<int, set<string> > s就定义上面描述的数据结构,和二维vector-样,两个> >中间的空格不能少了

这样我们就可以进行插入和查询了。比如:对2班的yuhaoran同学,我们s[2] . insert("yuhaoran")。然后查询yuhaoran是不是

-个2班的人,s[2]. count("yuhaoran")。然后还可以把他从2班删除s[2] . erase("yuhaoran")。

 map 套用 map 示例

遍历第二维:

#include<iostream>
#include<map>
#include<string>
using namespace std;
int main(){
    map<int,map<string,int> >info;
    int n;
    cin >> n;
    for(int i = 0;i < n;i++){
        int class_id;
        string name;
        cin >> class_id >> name;
        info[class_id][name]++;
    }
    for(map<int,map<string,int> > ::iterator it1 = info.begin(); it1 != info.end();it1++){
        for(map<string,int>::iterator it2 = it1->second.begin();it2 != it1->second.end();it2++){
            cout << "There are " << it2->second <<" people named " << it2->first <<" in class "<<it1->first <<"." << endl;
        }
    }
    return 0;
}

map<int, set<string>l > s就定义上面描述的数据结构,和二维vector-样,两个> >中间的空格不能少了。这样我们就可以进行插入和查询了。比如对2班的yuhaoran同学,我们s[2] . insert("yuhaoran")。然后查询yuhaoran是不是-个2班的人,s[2]. count("yuhaoran")。然后还可以把他从2班删除,s[2] . erase("yuhaoran")。

例题:打印锯齿矩阵

 

样例输入:

 

#include<stdio.h>
#include<iostream>
#include<vector>
using namespace std;
vector<int> mat[10005];
int main(){
    int n,m,x,y;
    cin >> n >> m;
    for(int i = 0; i < m;i++){
        cin >> x >> y;
        mat[x].push_back(y);
    }
    for(int i = 1; i <= n;i++){
        for(int j = 0; j < mat[i].size();j++){
            if(j != mat[i].size()){
                cout << mat[i][j] << " ";
            }else{
                cout << mat[i][j];
            }
        }
        cout << endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/expedition/p/12335904.html