STL入门

简介: 本文《STL入门》由blue编写,时间截至2024年3月。文章系统介绍了C++标准模板库(STL)中常用的容器与算法,包括`pair`、`set`、`vector`、`string`、`queue`、`deque`、`priority_queue`以及`list`的用法和实现细节。通过实例代码详细讲解了各容器的基本操作、初始化、遍历及应用场景,如`pair`的数据组合、`set`的自动去重、`vector`的动态数组特性、`string`的字符串处理、`queue`系列的队列操作以及`list`的双向链表特性。适合初学者快速掌握STL核心功能并应用于实际编程问题。

STL入门

作者:blue

时间:2024.3

[TOC]

0.概述

本文讨论部分常用的STL的运用

1.pair

pair是将2个数据组合成一组数据,

pair的实现是一个结构体,主要的两个成员变量是first second

pair<int ,double> p1;//注意中间要有逗号

p1.first = 1;

p1.second = 2.5;

cout<<p1.first<<' '<<p1.second<<endl;

//输出结果:1 2.5

还可以利用make_pair创建新的pair对象:

pair<int, double> p1;
p1 = make_pair(1, 1.2);        //make_pair
cout << p1.first << p1.second << endl;

//output: 1 1.2

int a = 8;

string m = "James";

pair<int, string> newone;

newone = make_pair(a, m);
cout << newone.first << newone.second << endl;

//output: 8 James

通过tie获取pair元素值

std::pair<std::string, int> getPreson() {
   
    return std::make_pair("Sven", 25);
}

int main(int argc, char **argv) {
   
    std::string name;
    int ages;

    std::tie(name, ages) = getPreson();

    std::cout << "name: " << name << ", ages: " << ages << std::endl;

    return 0;
}

2.set(集合)

集合是存储排序键的关联容器,其中每个键都是唯一的,可以插入或删除但不能更改。

begin() 返回一个指向集合中第一个元素的迭代器
end() 返回指向末尾的迭代器
empty() 如果set为空,则返回true
insert() 在集合中插入元素。
clear() 删除set容器中的所有的元素

初始化

template< class T,            
          class Compare = less<T>,    
          class Alloc = allocator<T>   
         > class set;

基本上就是三个参数,第一个是值,第二个比较器,用于比较内容,默认为less即降序,第三个是内存配置器,负责内存的分配和销毁。

在实际使用中,我们仅仅为其分配值就足以满足大部分需求。

set<int> s;    //直接指定值的类型创建,其他为默认方法
#include <iostream>
#include <set>
using namespace std;
int main()
{
                      /*两个‘>’之间最好有空格*/
    set<pair<double, double> > s;     //建立一个其中类型为pair<double,double>的集合,名为s
    int x1, y1, x2, y2;
    for (x1 = 0; x1 < 20; x1++)
    {
   
        for (y1 = 0; y1 < 21; y1++)
        {
   
            for (x2 = x1 + 1; x2 < 20; x2++)
            {
   
                for (y2 = 0; y2 < 21; y2++)
                {
   
                    double k = double(x1 - x2) / (y1 - y2);
                    double b = double(x2 * y1 - x1 * y2) / (x2 - x1);
                    s.insert({
    k,b });     //将元素值插入到集合s当中,集合会自动去重。
                }
            }
        }
    }
    printf("%lld", s.size() + 20);
    return 0;
}

set中元素的遍历

关键是要声明迭代器变量,遍历方法与数组类似,可以用while循环也可以用for循环,但用for循环时条件运算符不能用 <,而用 != 进行判断,还特别需要注意指针运算符

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

set<int>all;
int main()
{
   
    //生成待处理的数据
    for(int i=0;i<100;i++)
        all.insert(i);
    //遍历set,用迭代器类型
              ⬇️⬇️⬇️ 注意这种
    for(set<int>::iterator i=all.begin();i!=all.end();i++)
        cout<<*i<<endl; //注意指针运算符
    return 0;
}

3.vector

vector是一个十分有用的容器

简单地说,vector是一个能够\存放任意类型的动态数组*,能够增加和压缩数据。*

实例:
#include <iostream>
#include <vector>
#include <algorithm>
#define int long long
using namespace std;
signed main()
{
   
    int i;
    vector<int> a;           //定义
    for(i=0;i<=100;i++){
   
        a.push_back(i);      //尾部压入
    }
    for(i=0;i<a.size();i++)   //把其当数组来遍历 
    {
   
        printf("%lld ",a[i]);
    }
    reverse(a.begin(),a.end());   //逆转容器中的值 
    printf("\n");                        //⬇️,注意这里要用"!="
    for(vector<int>::iterator j=a.begin();j!=a.end();j++)  //把他用迭代器指针来遍历 
    {
   
                     //⬇️注意迭代器调用,用指针
        printf("%lld ",*j);
    }
    return 0; 
}

运行结果
image-20240317100800894.png

排序

sort(vec.begin(),vec.end());(默认是按升序排列,即从小到大).

bool cmp(int a,int b)
{
   
    return a>b;
}
调用时:sort(vec.begin(),vec.end(),Cmp),这样就降序排序。

4.string字符串类型

C++ string中的find()函数 - 王陸 - 博客园 (cnblogs.com)

为什么 string.find()返回值是-1_string中find函数-1为什么是18446744073709551615-CSDN博客

两篇文章结合着看

0顺子日期 - 蓝桥云课 (lanqiao.cn)

本题考查了对字符串类型的应用

#include <iostream>
#include <string>
using namespace std;
int main()
{
   
  int ans=0;
  string t1="012",t2="123";
  for(int i=1;i<=12;i++)
  {
   
    for(int j=1;j<=31;j++)
    {
   
      string str="2022";
      if(i>=10) str+=to_string(i);
      else{
   
        str+='0';
        str+=to_string(i);
      }
      if(j>=10) str+=to_string(j);
      else{
   
        str+='0';
        str+=to_string(j);
      }
      if(str.find(t1)!=-1||str.find(t2)!=-1) ans++;
    }
  }
  printf("%d",ans);
  return 0;
}

C++:cin、cin.getline()、getline()的用法_getline(cin,s)函数用法-CSDN博客

关于string,输入带空格或tab的字符串的有趣的用法。

C++中substr()函数用法详解_c++ substr-CSDN博客

string的用法总让人大吃一惊,还能这样用?

 s.substr(pos, len)
 //string a=s.substr(0,3);
 s中从pos开始的len个字符的拷贝

5.queue,deque,priority_queue

队列

queue<type> q
q.push(x) //将x放入队列
q.front() //返回队首元素但不删除
q.pop()   //删除队首元素
q.back()  //返回队尾元素
q.size()  //返回元素个数
q.empty() //检查队列是否为空,空则返回true

双端队列

由于双端队列,队首队尾都可以入队与出队的特点,他的入队出队操作与普通的queue不同,要格外注意

deque<type> dq
dp[i] //返回队列中下标为i的元素
dq.front() //返回队头
dq.back()  //返回队尾
dq.pop_back()//删除队尾,不返回值
dq.pop_front()//删除队头,不返回值
dq.push_back(x)//在队尾添加一个元素x
dq.push_front(x)//在队头添加一个元素x

双端队列的一个重要应用——单调队列

①单调队列与滑动窗口

#include <iostream>
#include <queue>
using namespace std;
int main()
{
              //数组从下标1开始存储,这个0是占位 
    int a[]={
   0,2,6,5,7,8,6};
    int m=3;//窗口的大小 
    deque<int> Q;//存放元素的下标 

    //滑动窗口的边界为  [i-m+1,i] 
    for(int i=1;i<=6;i++)  //维护窗口的最小值,保持队首元素永远是窗口内最小的 
    {
   
        while(!Q.empty()&&a[Q.back()]>a[i]) Q.pop_back();  //新进元素更优,队尾出队 
        Q.push_back(i);//存储的是下标 
        if(Q.front()<i-m+1) Q.pop_front(); //队首已在窗口之外,队首出队 
        if(i>=m) printf("%d ",a[Q.front()]);//窗口充满,可以输出 
    }

    printf("\n");

    for(int i=1;i<=6;i++) //维护窗口的最大值 
    {
   
        while(!Q.empty()&&a[Q.back()]<a[i]) Q.pop_back();
        Q.push_back(i);
        if(Q.front()<i-m+1) Q.pop_front();
        if(i>=m) printf("%d ",a[Q.front()]);
    } 
    return 0;
}

优先队列(priority_queue)

默认大顶堆

priority_queue <Type, Container, Functional> 队列名 //类型,容器类型,比较方式

priority_queue <int,vector<int>,greater<int> > q;//升序队列(最小值优先)

priority_queue <int,vector<int>,less<int> >q;    //降序队列,最大值优先(默认的)

由于优先队列是以堆的形式存储数据的,所以队首的元素应该是堆顶(top),这一点要和其他队列区分开来

q.size();//返回q里元素个数
q.empty();//返回q是否为空,空则返回1,否则返回0
q.push(k);//在q的末尾插入k
q.pop();//删掉q的第一个元素
q.top();//返回q的第一个元素

自定义优先级(要注意和自定义排序区分开,不要搞混了)
image-20240411220148782.png

结构体自定义优先级

image-20240411220750502.png

6.list的用法

详解C++STL容器系列(二)—— list的详细用法和与vector的对比_vector assign swap 区别-CSDN博客

掌握stl中list的用法

P1996 约瑟夫问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include <iostream>
#include <list>
using namespace std;
int main()
{
   
    int n,m;
    cin>>n>>m;
    list<int> a;
    for(int i=1;i<=n;i++) a.push_back(i);
    list<int>::iterator it=a.begin();
    while(a.size()>1)
    {
   
        for(int i=1;i<m;i++){
   
            it++;
            if(it==a.end()) it=a.begin();
        }
        cout<<*it<<" ";
        list<int>::iterator next=++it;
        if(next==a.end()) next=a.begin();//end()成员函数返回指向末尾位置的迭代器。这个“末尾位置”            指的是最后一个元素再往后一位,也就是说end()所指的位置不包含有效元素,它相当于一个虚设的节点。
        a.erase(--it);
        it=next;
    }
    cout<<*it;
    return 0;
}
目录
相关文章
|
SQL 关系型数据库 MySQL
MySQL InnoDB中的锁-临键锁(next-key lock)
MySQL InnoDB 锁 临键锁 next-key lock
2499 0
MySQL InnoDB中的锁-临键锁(next-key lock)
|
SQL 关系型数据库 MySQL
菜鸟之路Day30一一MySQL之DML&DQL
本文介绍了MySQL中DML(数据操作语言)和DQL(数据查询语言)的核心用法。DML主要包括插入(insert)、更新(update)和删除(delete)语句,通过具体示例演示了如何对表数据进行增删改操作。DQL则聚焦于数据查询,涵盖基本查询、条件查询、聚合函数、分组查询、排序查询和分页查询等内容。文章通过丰富的SQL语句实例,帮助读者掌握如何高效查询和操作数据库中的数据,适合初学者学习和实践。
403 12
|
SQL 存储 关系型数据库
菜鸟之路Day29一一MySQL之DDL
本文《菜鸟之路Day29——MySQL之DDL》由作者blue于2025年5月2日撰写,主要介绍了MySQL中的数据定义语言(DDL)。文章详细讲解了DDL在数据库和表操作中的应用,包括数据库的查询、创建、使用与删除,以及表的创建、修改与删除。同时,文章还深入探讨了字段约束(如主键、外键、非空等)、常见数据类型(数值、字符串、日期时间类型)及表结构的查询与调整方法。通过示例代码,读者可以更好地理解并实践MySQL中DDL的相关操作。
396 11
|
算法
蓝桥杯16天刷题计划一一Day02
这是蓝桥杯16天刷题计划的第二天内容,由作者blue于2025年3月28日整理。当天训练重点为二分法,包含多道经典题目解析与代码实现,如有序数组查找、砍树问题、木材加工等。文章针对二分法的应用场景进行了深入讲解,并通过实例演示了如何优化算法效率,适合对二分法不熟悉的初学者学习和练习。
361 5
|
关系型数据库 MySQL 数据安全/隐私保护
MySQL下载与安装
本文介绍了MySQL的下载与安装流程(2025.4.29,作者:blue)。主要内容包括:1) 从官方地址下载MySQL;2) 解压文件并配置环境变量;3) 注册MySQL服务并通过命令行验证;4) 启动和停止MySQL服务;5) 修改默认账户密码;6) 登录MySQL。通过详细步骤和截图,帮助用户顺利完成安装与初始配置。
3056 13
|
缓存 负载均衡 安全
Nginx的反向代理具体是如何实现的?
Nginx的反向代理具体是如何实现的?
1219 156
|
前端开发 Java 程序员
菜鸟之路Day28一一分层解耦
本文《菜鸟之路Day28——分层解耦》由作者blue撰写于2025年4月29日,主要探讨软件开发中的三层架构与分层解耦概念。文章首先介绍了三层架构:Controller(控制层)、Service(业务逻辑层)和DAO(数据访问层),并深入讲解了“高内聚低耦合”的软件设计原则。接着,文章详细说明了控制反转(IOC)与依赖注入(DI)的实现方式,包括如何通过注解声明Bean对象、组件扫描以及解决多Bean冲突的方法(如@Primary、@Qualifier和@Resource)。内容结合实际开发场景,为初学者提供了清晰的指导。
433 15
|
存储 算法 C语言
高精度算法
本文详细介绍了高精度算法的实现,涵盖加法、减法、乘法、除法及取模等操作。通过字符串与数组结合的方式,解决了大数运算中超出数据类型范围的问题。每种运算均提供完整的C++代码示例,包括输入处理、位运算模拟、进位/借位逻辑以及结果输出。其中,高精度加法和减法通过逆序存储数字简化计算;乘法利用双重循环模拟手算过程;除法分为低精度和高精度两种情况,分别采用逐位试商与减法模拟;取模则通过逐位累加求余实现。这些方法为处理大规模数值运算提供了有效工具,适用于竞赛编程与实际开发场景。
536 24
|
JavaScript 前端开发 应用服务中间件
菜鸟之路Day24一一前端工程化(一)
本文详细介绍了从零开始搭建Vue前端项目并部署到Nginx服务器的全流程。首先,通过配置Node.js和vue-cli环境,为项目创建打好基础。接着,利用vue-cli快速生成Vue项目,可通过命令行或图形化界面完成配置,如添加路由功能等。文章还解析了Vue项目的结构,重点讲解组件的概念及实现方式,并通过编写登录页面组件演示开发过程。最后,展示了如何修改端口、启动项目以及组件挂载的原理,帮助读者深入理解Vue工程化开发的核心思想。
420 4
菜鸟之路Day24一一前端工程化(一)
|
存储 自然语言处理 算法
蓝桥杯16天刷题计划一一Day01(STL练习)
本文介绍了蓝桥杯16天刷题计划的第一天内容,主要练习STL相关算法。涵盖队列、优先队列、单调队列、单调栈和链表等数据结构的应用。通过经典题目如机器翻译(队列模拟内存)、约瑟夫问题(链表模拟报数)、滑动窗口(单调队列)、Look Up(单调栈)、合并果子(优先队列)和最小函数值(优先队列结构体排序),详细解析了每种数据结构的实现与优化方法,并附有完整代码示例。适合初学者掌握STL核心用法及算法思想。
435 10