STL总结:(queue队列)(pair)(set集合)(stack栈)(priority_queue优先队列)

queue队列

(1)特点:

只能访问容器的第一个和最后一个元素
只能在容器的末尾添加新的元素
只能从头部移出元素
先进先出(FIFO,First in first out)

(2)定义:

queue<数据类型>名称;

queue<int>q1;
queue<char>q2;

(3)函数

back()返回最后一个元素
empty()如果队列为空返回true
front()返回队首元素
pop()删除队首元素
push()在末尾加入一个元素
size()返回队列中元素的个数

基本操作:

q1.push(1);//向q1这个队列中插入1这个数字
int len=q1.size();
int a=q1.fount();

练习题(1):

东秦oj 练手题
题目描述:
队列操作题。根据输入的操作命令,操作队列(1)入队、(2)出队并输出、(3)计算队中元素个数并输出。
输入:
第一行一个数字N。 下面N行,每行第一个数字为操作命令(1)入队、(2)出队并输出、(3)计算队中元素个
数并输出。
输出:
若干行每行显示一个2或3命令的输出结果。注意:2.出队命令可能会出现空队出队(下溢),请输出“no”,并退
出。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    queue<int>q;
    int n,a,b;
    cin>>n;
    while(n--)
    {
        cin>>a;
        if(a==1)
        {
            cin>>b;
            q.push(b);
        }
        if(a==2)
        {
            if(!q.empty())
            {
                cout<<q.front()<<endl;
                q.pop();
            }
            else
            {
                 cout<<"no"<<endl;
                 break;
            }
        }
        if(a==3)
        {
            cout<<q.size()<<endl;
        }
    }
    return 0;
}

练习题(2):

题目描述:
某不对进行新兵队列训练,将新兵从一开始按照顺序依次编号,并排成一行横队,训练的规则如下:
从头开始1到2报数,凡是报到2的就出列,剩下的人向小序号方向靠拢。再从头进行1到3报数,凡是报到3的就出列,剩下的人还是向小序号方向靠拢,继续从头开始从1到2报数。。。
以后从头开始轮流进行1到2,1到3报数,直到剩下的人数不超过3为止。
思路:用队列模拟,

#include<bits/stdc++.h>
using namespace std;
int main()
{
    queue<int>q;
    int n,t;
    cin>>t;
    while(t--)
    {
        cin>>n;
        for(int i=1;i<=n;i++)
            q.push(i);
        int flag=1;//标记是怎样报数,开始是flag=1;1 2报数
        while(q.size()>3)
        {
            if(flag&1)
            {
                int num=q.size();//目前有多少人
                for(int i=1;i<=num;i++)
                {
                    if(i%2==0)
                        q.pop();
                    else
                    {
                        q.push(q.front());
                        q.pop();
                    }
                }
                flag=0;//此后就是1 3报数
            }
            else
            {
                int num=q.size();
                for(int i=1;i<=num;i++)
                {
                    if(i%3==0)
                        q.pop();
                    else
                    {
                        q.push(q.front());
                        q.pop();
                    }
                }
                flag=1;
            }
        }
        //再控制一下输出格式末尾不能有空格
        printf("%d",q.front());
        q.pop();
        while(!q.empty())
        {
            printf(" %d",q.front());
            q.pop();
        }
        printf("\n");
    }
    return 0;
}

在这里插入图片描述

pair

pair就是一个结构体,但是比结构体更加灵活,一般使用typedef优化,
pair<T1,T2>中T1和T2可以是不同的数据类型

(1)定义

pair<int,int>p1;
pair<int,double>p2(1,2.5);    //定义的同时 还初始化了
pair<int double>p3(p2);     //拷贝构造函数

(2)访问:通过first和second

p1.first=1;
p1.second=2;
cout<<p1.first<<" "<<p1.second<<endl;

(3)赋值用make_pair

pair<int,double>p4;
p4=make_pair(1,2.38);
p5=p4;     //变量间赋值

(4)应用:

如果一个函数有两个返回值 的话,如果是相同类型,就可以用数组返回,如果是不同类型,就可以自己写个
struct ,但为了方便就可以使用 c++ 自带的pair ,返回一个pair,其中带有两个值。除了返回值的应用,在一个对象
有多个属性的时候 ,一般自己写一个struct ,如果就是两个属性的话,就可以用pair 进行操作

(5)练习:关于pair在做题里面的应用(主要是和sort联用)

东秦oj
成绩排序
题目大意:输入n个学生的姓名和成绩,排序后输出
题解:这里是每一个数据由两个部分组成:姓名和成绩。
建一个pair<string,int> 的结构体数组,然后用stl自带sort进行排序,
法一:

#include<bits/stdc++.h>
using namespace std;
typedef pair<string,int>p;//起个别名
p arr[101];
int n;
bool cmp(p a,p b)
{
    return a.second>b.second;
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>arr[i].first>>arr[i].second;
    sort(arr,arr+n,cmp);
    for(int i=0;i<n;i++)
        cout<<arr[i].first<<" "<<arr[i].second<<endl;
    return 0;
}

还有一个简单写法。 在sort排序的时候,对于pair类型数据默认按照first进行升序排序,所以咱们完全可以把成绩放入first,输出的时候先输出second,再输出first。(就不用自己写自定义比较函数了)

扫描二维码关注公众号,回复: 5626716 查看本文章
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,string> P;
//起个别名 !!!这里有变化,交换数据类型的位置,把int放在first的位置,以便排序
P arr[101]; //结构体数组
int n;
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)             //输入顺序先second,以为要先输入姓名,再输入成绩
        cin>>arr[i].second>>arr[i].first;
    sort(arr,arr+n);            //默认升序排序
    for(int i=n-1;i>=0;i--)          //这里要倒序输出,
    cout<<arr[i].second<<" "<<arr[i].first<<endl;
    return 0;
}

set集合

在这里插入图片描述

(1)特点:

set中元素是排好序的,从小到大(默认升序排列)
set中没有重复元素

(2)定义:

//set<数据类型>名称;
set<int>s;

(3)常用函数:

s.begin();     //返回指向容器 最开始位置 数据的       ==指针==
s.end();     //返回指向容器最后一个数据单元     ==+1的指针== 
s.insert();     //插入
s.clear();     //清空
s.empty();     //判断set是否为空
s.size();     //返回set中元素的个数
s.erase();     //删除迭代器指针it处元素
s.count(x)      //返回x出现的次数(因为是集合 只可能是0或1)

注意:插入规则在默认的比较规则下,是按元素值从小到大插入,如果自己指定了比较规则函数,则按自定义比较规则函数插入。

set<int>::iterator it; //定义前向迭代器
set<int>::reverse_iterator rit; //定义反向迭代器

看这两个代码:

#include<iostream>
#include<set>
using namespace std;
int main()
{
	set<int> s;
	
	s.insert(5); //第一次插入5,可以插入
	s.insert(1);
	s.insert(6);
	s.insert(3);
	s.insert(5); //第二次插入5,重复元素,不会插入
	
	set<int>::iterator it; //定义前向迭代器
	//中序遍历集合中的所有元素
	for(it = s.begin(); it != s.end(); it++)
	{
		cout << *it << " ";
	}
	//cout <<s.end()<< endl;报错
	cout << endl;
	return 0;
}


//运行结果:1 3 5 6

第二个代码:
(元素的方向遍历
使用反向迭代器reverse_iterator可以反向遍历集合,输出的结果正好是集合元素的反向排序结果。
它需要用到 rbegin()和rend() 两个方法,
它们分别给出了反向遍历的开始位置和结束位置。)

#include<iostream>
#include<set>
using namespace std;
int main()
{
	set<int> s;
	
	s.insert(5); //第一次插入5,可以插入
	s.insert(1);
	s.insert(6);
	s.insert(3);
	s.insert(5); //第二次插入5,重复元素,不会插入
	
	set<int>::reverse_iterator rit; //定义反向迭代器
	//反向遍历集合中的所有元素
	for(rit = s.rbegin(); rit != s.rend(); rit++)
	{
		cout << *rit << " ";
	}
	cout << endl;
	return 0;
}


//运行结果:6 5 3 1

(4)元素的删除s.erase(键值);

    与插入元素的处理一样,集合具有高效的删除处理功能,并自动重新调整内部的红黑树的平衡。
    删除的对象可以是某个迭代器位置上的元素、等于某键值的元素、一个区间上的元素和清空集合。
#include<iostream>
#include<set>
using namespace std;
int main()
{
	set<int> s;
	s.insert(5); //第一次插入5,可以插入
	s.insert(1);
	s.insert(6);
	s.insert(3);
	s.insert(5); //第二次插入5,重复元素,不会插入
	//此时s中是1,3,5,6
	s.erase(6); //删除键值为6的元素
	//1,3,5
	set<int>::reverse_iterator rit; //定义反向迭代器
	//反向遍历集合中的所有元素
	for(rit = s.rbegin(); rit != s.rend(); rit++)
	{
		cout << *rit << " ";
	}
	cout << endl;	
		//5,3,1
	set<int>::iterator it;
    //1,3,5
	it = s.begin();
	for(int i = 0; i < 2; i++)
		it = s.erase(it); 
    //5
	for(it = s.begin(); it != s.end(); it++)
		cout << *it << " ";
	cout << endl;
	/*输出也可以用:
	while(!s.empty())
	{
		cout<<*s.begin()<<" "; //注意此处的用法
		s.erase(s.begin());
	}
 	*/
 	
	s.clear();
	cout << s.size() << endl;
    //0
	return 0;
}


/*
运行结果:
5 3 1
5
0    
*/

(5)元素的检索

使用find()方法对集合进行检索,如果找到查找的的键值,则返回该键值的 迭代器位置 ;否则,返回集合最后一个元素后面的一个位置,即end()。

#include<iostream>
#include<set>
using namespace std;
int main()
{
	set<int> s;
	s.insert(5); //第一次插入5,可以插入
	s.insert(1);
	s.insert(6);
	s.insert(3);
	s.insert(5); //第二次插入5,重复元素,不会插入
	//1,3,5,6
	set<int>::iterator it;
	it = s.find(6); //查找键值为6的元素
	if(it != s.end())
		cout << *it << endl;
	else
		cout << "not find it" << endl;
	it = s.find(20);
	if(it != s.end())
		cout << *it << endl;
	else
		cout << "not find it" << endl;
	return 0;
}
/*
运行结果:
6
not find it   
*/

(6)自定义比较函数

使用insert将元素插入到集合中去的时候,集合会根据设定的比较函数奖该元素放到该放的节点上去。在定义集合的时候,如果没有指定比较函数,那么采用 默认的比较函数,是按键值从小到大的顺序插入元素。但在很多情况下,需要自己编写比较函数。

编写比较函数有两种方法。

(1)如果元素不是结构体,那么可以编写比较函数。下面的程序比较规则为 按键值从大到小的顺序插入到集合中

#include<iostream>
#include<set>
using namespace std;
struct mycomp
{ 
    //自定义比较函数,重载“()”操作符
	bool operator() (const int &a, const int &b)
	{
		if(a != b)
			return a > b;
		else
			return a > b;
	}
};
int main()
{
	set<int, mycomp> s; //采用比较函数mycomp
	
	s.insert(5); //第一次插入5,可以插入
	s.insert(1);
	s.insert(6);
	s.insert(3);
	s.insert(5); //第二次插入5,重复元素,不会插入
	set<int,mycomp>::iterator it;
	for(it = s.begin(); it != s.end(); it++)
		cout << *it << " ";
	cout << endl;
	return 0;
}

/*
运行结果:6 5 3 1  
*/

(2)如果元素是结构体,那么可以直接把比较函数写在结构体内。

#include<iostream>
#include<set>
#include<string>
using namespace std;
struct Info
{
	string name;
	double score;
	bool operator < (const Info &a) const // 重载“<”操作符,自定义排序规则
	{
		//按score由大到小排序。如果要由小到大排序,使用“>”即可。
		return a.score < score;
	}
};
int main()
{
	set<Info> s;
	Info info;
 
	//插入三个元素
	info.name = "Jack";
	info.score = 80;
	s.insert(info);
	info.name = "Tom";
	info.score = 99;
	s.insert(info);
	info.name = "Steaven";
	info.score = 60;
	s.insert(info);
 
	set<Info>::iterator it;
	for(it = s.begin(); it != s.end(); it++)
		cout << (*it).name << " : " << (*it).score << endl; 
	return 0;
}

/*
运行结果:
Tom : 99
Jack : 80
Steaven : 60
*/

stack栈

(1)特点:

只能访问栈顶元素,
插入删除只能在栈顶操作
插入叫入栈,删除叫出栈
后进先出
在这里插入图片描述

(2)定义

stack<int> s; //stack<数据类型> 名称;
stack<double> s;

(3)函数

s.empty() //判断栈是否为空
s.size() //返回栈中元素个数
s.pop() //删除栈顶元素
s.top() //返回栈顶元素但不删除该元素
s.push(x) //在栈顶压入新元素

练习:橙白时光2628(密码比对器)

Description

在 Ubuntu 等一系列类似 Linux 系统终端中,输入密码是不可见的,这就需要你记住你所输入的内容。因为是不可见的,有时候可能输入错误,或者自己忘记输入的是什么了,这时你可以通过拼命的按退格键来删除你刚才输入的内容。当然,如果你什么都没有输入或者把之前的东西删光了,按退格键是没有任何效果的。
假设密码允许输入大小写字母和数字, “@”符号代表退格。 现在给你一个包含大小写字母和数字的序列,代表用户的输入,以及一个正确的密码,请聪明的你来实现一个简单的密码比对器, 验证用户的输入和正确密码是否相同。

Input

输入共有两行,分别为正确密码和用户的输入,题目保证用户的输入和正确密码不超过 1000 位,且输入非空。

Output

如果用户的输入与正确密码一致,输出 “True”,否则输出“False”

Sample Input
123456
123abc@@@@@@@@@654321

Sample Output
False

#include<bits/stdc++.h>
using namespace std;
stack<char>st;
int main()
{
    string a,b,s;		   //a是最终目标,b是要处理的字符串,s是接收处理好的字符串的
  							  //在st栈中遍历b,用s接收处理好的,再与a比较
    cin>>a>>b;
    int len=b.size();
    for(int i=0;i<len;i++)
    {
        if(b[i]=='@' && !st.empty())
            st.pop();
        else
        {
            if(b[i]!='@')
                st.push(b[i]);
        }
    }
    //用string类型的s接收过来
    while(!st.empty())
    {
        s += st.top();
        st.pop();
    }
    reverse (s.begin(),s.end());  //翻转
    if(s==a)
        cout<<"True"<<endl;
    else
        cout<<"Elase"<<endl;
    return 0;
}

priority_queue优先队列

(1)特点:默认排好序的,默认降序,从大到小

(2)定义:

//默认定义:
priority_queue<int> q;

//手动定义 推荐使用此方法
priority_queue <int,vector<int>,less<int> >q;      //降序 从大到小
priority_queue <int,vector<int>,greater<int> >q;      //升序 从小到大

(3)函数:

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

(4)举个例子

#include<bits/stdc++.h>
using namespace std;
int main(void)
{
priority_queue<int,vector<int>,greater<int> > q;
//乱序插入
q.push(3);
q.push(6);
q.push(1);
//遍历
while(!q.empty())
{
cout<<q.top()<<" ";
q.pop();
}
return 0;
}

在这里插入图片描述

举一个贪心的题 poj3253

题目大意:
有一堆木棒,最后合成一根,求花费体力最小.
比如长度是3 5 8 合成一个
首先是3和5合成长度为8的,耗费8个体力
此时剩两根木棒8 8
再合成一个8+8耗费16体力
总共耗费8+16=24个体力
题解:思路就是,每次都找两个最小的 ,把他们合成一个,才能保证合成的那个尽量小,保证接下来合成每次都是最优的解,这就是 贪心的思路,局部最优解,达到全局最优解
用优先队列很好实现,每次取队列两个最小值,合成之后插入队列里。直到只剩一根

#include<iostream>
#include<queue>
using namespace std;
typedef long long ll;
priority_queue<int,vector<int>,greater<int> > q; //从小到大的队列
int n,a;
ll sum; //卡ll,int过不去
int main(void)
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a;
        q.push(a);
    }
    while(q.size()!=1) //合成一根结束
    {
        int t1=q.top(); //取第一个
        q.pop();//记得弹出才能取下一个
        int t2=q.top();//取第二个
        q.pop();
        int t3=t1+t2; //合成
        sum+=t3; //sum记录总的消费
        q.push(t3); //再把合成的插入
    }
    cout<<sum<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43250284/article/details/87026673