栈 & 队列 & 优先队列 & map & set & vector

本文详细介绍了C++中的几种重要容器:栈、队列、优先队列、map、set和vector。通过实例解析它们的特性和使用方法,如栈的先进后出特性在括号匹配问题中的应用,队列在处理特定问题时的作用,优先队列在解决最小花费问题中的优势,以及map和set在数据管理中的功能。同时,还展示了vector作为动态数组的灵活性。

栈和队列相似但是不同,不同的是队列先进先出从末尾进排头出,栈像一个瓶子容器,从瓶口进,瓶口出,先进的在瓶底所以后出,所以栈的特点 先进后出,后进先出。然后下面讲用法和例题。

#include<stack>
stack<char(可以是int等)> q(名字);
q.push(a);     //将a入栈
q.pop();       //将栈顶出栈
q.top();       //栈顶的值
q.empty();     //判断是否为空

例题:假设一个表达式有英文字母(小写)、运算符(+,—,*,/)和左右小(圆)括号构成,以“@”作为表达式的结束符。请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配,则返回“YES”;否则返回“NO”。表达式长度小于255,左圆括号少于20个。

输入输出格式
输入格式:
一行:表达式

输出格式:
一行:“YES” 或“NO”

输入输出样例

输入样例#1:
2*(x+y)/(1-x)@
输出样例#1:
YES

输入样例#2:
(25+x)(a(a+b+b)@
输出样例#2:
NO

题解:将所有左括号挨着入栈,然后每次出现右括号就去判断栈里面是否有左括号,如果有就继续,没有说明不合理就NO

代码:

    #include<stdio.h>
    #include<stdlib.h>
    #include<math.h>
    #include<string.h>
    #include<queue>
    #include<algorithm>
    #include<iostream>
    #define exp 1e-9
    #define PI acos(-1.0)
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef unsigned long long LL;
    stack<char> zhan;
    int main() 
    {
        char input;
        while(scanf("%c",&input)&&input!='@') 
        {
            if(input=='(') 
               zhan.push(input);//入栈 
            if(input==')') {
                if(zhan.empty()) //判断栈是否为空即可 
                {
                    printf("NO\n");//也许大家会问,为啥不来个if(zhan.top()=='(' )呢,因为 这题只有小括号 而且会超时
                    return 0;//至于为啥要判断栈是否为空,大家想想,因为假如有个),结果前面没有对应(了,那就不行,此时就是栈空 
                }
                zhan.pop();//出栈 
            }
        }
        if(zhan.empty())
            printf("YES\n");//判断有没有多余的(
        else 
            printf("NO\n");//也就是判断栈是否为空 
        return 0;
    }

队列

队列就是一行人排在一起,先进去的人排在第一个,后进去的人排在后面,所以队列的特点先进先出,这个是很重要的。在处理一些特殊问题的时候,队列是非常有用的。下面主要讲用法和例题。

  #include<queue>   //要包含头文件
  int a,b,c;  
  queue<int> q1;       //定义q1 队列  <>中的为数据类型
  q1.push(3);          //把3压入队列,接到队列的末端
  q1.pop();            //删除队列的第一个元素,注意,并不会返回被弹出元素的值,只是删除
  a =  q1.front();     //返回队例首元素 ,不删除, a为队列的第一个元素
  b = q1.back();       //同上一样,返回队例尾元素
  c = q1.size();      // c等于q1现在包含的元素的个数【个数】 
  q.empty()            //q队列为空时返回真。

例题:n个人(n<=100)围成一圈,从第一个人开始报数,数到m的人出列,再由下一个人重新从1开始报数,数到m的人再出圈,……依次类推,直到所有的人都出圈,请输出依次出圈人的编号.

输入输出格式
输入格式:
n m

输出格式:
出圈的编号

输入输出样例
输入样例#1:
10 3
输出样例#1:
3 6 9 2 7 1 8 5 10 4
说明
m,n≤100

题解:这是一道比较典型的队列题,一个一个进入队列,报道m的就出列然后输出,不是m的就继续排到末尾。

代码

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<iostream>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
using namespace std;
typedef unsigned long long LL;
int main()
{
    int n,m,nownum=1;
    queue<int>q;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        q.push(i);  //  入队
    while(!q.empty())
    {
        if(nownum==m)
        {
            printf("%d ",q.front()); //输出编号
            q.pop(); //出队
            nownum=1;
        }
        else
        {
            nownum++;
            q.push(q.front()); //排至队尾
            q.pop();//出队
        }
    }
    return 0;
}

优先队列

自动排序的队列

#include<queue>
using namespace std;

这两个头文件。

其次,一个优先队列声明的基本格式是:
priority_queue<结构类型> 队列名;
比如

priority_queue <int> q; 

//这样是从大到小拿出

priority_queue<int , vector<int> , greater<int> >q;

//这样是从小到大拿出

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

例题:给定一个木条,锯成input中要求的段数和每一段的长度,每锯一次花费锯成被锯成两半的木条长度之和,求最小花费

题解:每次把最小的两个数合并就行。用优先队列处理合适。

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define mod 1000000007
using namespace std;
typedef long long LL;
int a[20005];
int ans=0,n;
void solve()
{
    priority_queue<int , vector<int> , greater<int> >q; //定义从小到大拿出的优先队列
    for(int i=1;i<=n;i++)
        q.push(a[i]); //全部入队
    while(q.size()>1)
    {
        int l1=q.top();
        q.pop();
        int l2=q.top();
        q.pop();
        ans+=(l1+l2); 
        q.push(l1+l2); //把最小两个的和继续入队
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    solve();
    printf("%d\n",ans);
	return 0;
}

例题:你须要开着一辆卡车行驶L单位距离,最開始卡车有P单位汽油,卡车每开一单位距离须要消耗1单位汽油。如果在中途卡车汽油耗尽,卡车就无法继续前行。到不了终点。在途中一共同拥有n个加油站。告诉你每一个加油站距离终点的距离和每一个加油站能够加的油量,如果卡车的油箱是无穷大的,问卡车至少要加多少次油才干到达终点?卡车到不了终点输出-1;

输入n,l,p。n为加油站数目,l为距离,p为油量
输入n个数据a[i] 代表每个加油站的位置
输入n个数据b[i] 代表每个加油站对应可以加的油量

题解:把思路转化为路过一个加油站,就先放入优先队列中,因为优先队列可以把最大的放在最上面。然后只要油量不够,就拿出优先队列最上面个,如果拿不出,则输出-1无法到达。

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<map>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define mod 1000000007
using namespace std;
typedef long long LL;
int n,l,p;
int a[105],b[105];
void solve()
{
    a[n]=l;
    b[n]=0;
    n++;
    //终点看成加油站
    priority_queue<int>q;
    int ans=0,pos=0,tank=p;
    //ans为加油次数,pos为当前位置,tank为当前油量
    for(int i=0;i<n;i++)
    {
        int d=a[i]-pos;
        //油量不够
        while(tank-d<0)     
        {
            if(q.empty())
            {
                printf("-1\n");
                return;
            }
            tank+=q.top();
            q.pop();
            ans++;
        }
        //油量足够
        tank-=d;
        pos=a[i];
        q.push(b[i]);
    }
    printf("%d\n",ans);
}
int main()
{
    scanf("%d%d%d",&n,&l,&p);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    for(int i=0;i<n;i++)
        scanf("%d",&b[i]);
    solve();
	return 0;
}

map

map的基本操作函数:

     C++ maps是一种关联式容器,包含“关键字/值”对

     begin()         返回指向map头部的迭代器

     clear()        删除所有元素

     count()         返回指定元素出现的次数

     empty()         如果map为空则返回true

     end()           返回指向map末尾的迭代器

     equal_range()   返回特殊条目的迭代器对

     erase()         删除一个元素

     find()          查找一个元素

     get_allocator() 返回map的配置器

     insert()        插入元素

     key_comp()      返回比较元素key的函数

     lower_bound()   返回键值>=给定元素的第一个位置

     max_size()      返回可以容纳的最大元素个数

     rbegin()        返回一个指向map尾部的逆向迭代器

     rend()          返回一个指向map头部的逆向迭代器

     size()          返回map中元素的个数

     swap()           交换两个map

     upper_bound()    返回键值>给定元素的第一个位置

     value_comp()     返回比较元素value的函数

例题:Registration system

在不久的将来,一种新的电子邮件服务 “Berlandesk” 将在 Berland 开放。网站管理员想要尽快发布他们的项目,因此请您提供帮助。请实现网站注册系统的原型。该系统应当按以下的原理工作。

每当一个新的用户想要注册时,他向系统发送一个包含了自己 name 的请求。如果系统数据库中不存在这样的 name ,则它被插入到数据库中,并且用户获得反馈 OK ,确认注册成功。如果系统数据库中已存在该 name ,则系统创建一个新的用户名,将它发送给用户作为提示,且将提示信息也插入数据库中。新的用户名按如下规则构成。以 1 开头的数字被逐一追加到 name 的尾部 (name1, name2, …),其中最小的 i 被找到,使得数据库中尚不存在 namei 。

输入
第一行包含了数字 n (1?≤?n?≤?105)。接下来的 n 行包含了对系统的请求。每个请求是非空的一行,由不超过 32 个字符组成,各字符均为小写的拉丁字母。

输出
打印 n 行,作为对请求作出的系统反馈:如果注册成功,则打印 OK ;如果请求的用户名已被占用,则打印新的用户名。

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<map>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
char str[1000050];
int main()
{
    int n;
    map<string,int> s;
    string str;
    while(~scanf("%d",&n))
    {
        cin>>str;
        s[str]++;
        if(s[str]>1)
            cout<<str<<s[str]-1<<endl;
        else
            printf("OK\n");

    }
    return 0;
}

set

set,顾名思义,就是数学上的集合——每个元素最多只出现一次,并且set中的元素已经从小到大排好序。

头文件:#include

常用的函数:

begin()        返回set容器的第一个元素的地址
end()        返回set容器的最后一个元素地址
clear()        删除set容器中的所有的元素
empty()       判断set容器是否为空
max_size()      返回set容器可能包含的元素最大个数
size()        返回当前set容器中的元素个数
erase(it)        删除迭代器指针it处元素
insert(a)        插入数据a

例题:
洛谷P1059 明明的随机数
题目描述
明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作。

输入输出格式
输入格式:
输入有两行,第11行为11个正整数,表示所生成的随机数的个数N
第2行有N个用空格隔开的正整数,为所产生的随机数。

输出格式:
输出也是两行,第1行为1个正整数M,表示不相同的随机数的个数。

第2行为M个用空格隔开的正整数,为从小到大排好序的不相同的随机数。

输入输出样例
输入样例#1: 复制
10
20 40 32 67 40 20 89 300 400 15
输出样例#1: 复制
8
15 20 32 40 67 89 300 400

题解
利用了SET容器的特性每个元素只有一个。

代码

#include<bits/stdc++.h>
using namespace std;
set<int>s;
int a[105];
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
        s.insert(a[i]);
    }
    cout<<s.size()<<endl;
    while(!s.empty())
    {
        cout<<*s.begin()<<" ";           //注意此处的用法
        s.erase(s.begin()); 
    }
    return 0;
 }

Vector

vector(向量): C++中的一种数据结构,确切的说是一个类.它相当于一个动态的数组,当程序员无法知道自己需要的数组的规模多大时,用其来解决问题可以达到最大节约空间的目的.

      1.文件包含:     

       首先在程序开头处加上#include<vector>以包含所需要的类文件vector

      还有一定要加上using namespace std;



      2.变量声明:

           2.1 例:声明一个int向量以替代一维的数组:vector <int> a;(等于声明了一个int数组a[],大小没有指定,可以动态的向里面添加删除)。

           2.2 例:用vector代替二维数组.其实只要声明一个一维数组向量即可,而一个数组的名字其实代表的是它的首地址,所以只要声明一个地址的向量即可,即:vector <int *> a.同理想用向量代替三维数组也是一样,vector <int**>a;再往上面依此类推.

详细的函数实现功能:其中vector c.

                  c.clear()         移除容器中所有数据。

                  c.empty()         判断容器是否为空。

                  c.erase(pos)        删除pos位置的数据

                  c.erase(beg,end) 删除[beg,end)区间的数据

                  c.front()         传回第一个数据。

                  c.insert(pos,elem)  在pos位置插入一个elem拷贝

                  c.pop_back()     删除最后一个数据。

                  c.push_back(elem) 在尾部加入一个数据。

                  c.resize(num)     重新设置该容器的大小

                  c.size()         回容器中实际数据的个数。

                  c.begin()           返回指向容器第一个元素的迭代器

                  c.end()             返回指向容器最后一个元素的迭代器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值