STL和基本的数据结构

STL概念

STL(Standard Template Library)是C++的标准模板库,竞赛中很多常用的数据结构算法在STL中都有。STL包含容器(contaniner),迭代器(interator),空间配置器(allocator),配接器(adapter),算法(algorithm),仿函数(function)6个部分。

顺序式容器

顺序式容器包括:vector,list,deque,queue,priority_queue,stack等。

vector:动态数组,从末尾能快速插入与删除,直接访问任何元素。
list:双链表,从任何地方快速插入与删除。
deque:双向队列,从前面或后面快速插入与删除,直接访问任何元素。
queue:队列,先进先出。
priority_queue:优先队列,最高优先级元素总是第一个出列。
stack:栈,后进先出。

Vector

vector是STL的动态数组,在运行时能根据需要改变数组大小。内存空间是连续的。

1.定义
在这里插入图片描述
2.常用操作
在这里插入图片描述
3.运用
在这里插入图片描述

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;

int main()
{
    int n,m;
    vector<int>table;
    while(~scanf("%d %d",&n,&m))
    {
        table.clear();//清空数据
        for(int i=0;i<2*n;i++)
        {
            table.push_back(i);//初始化,编号
        }
        int pos=0;
        for(int i=0;i<n;i++)
        {
            pos=(pos+m-1)%table.size();//圆桌是个环,取余处理
            table.erase(table.begin()+pos);//赶走坏人,table人数减1
        }
        int j=0;
        for(int i=0;i<2*n;i++)
        {
            if(!(i%50)&&i)//50个字母一行
                printf("\n");
            if(j<table.size()&&i==table[j])//赶走坏人之后,编号和原来一样的是留下来的好人
            {
                j++;
                printf("G");
            }
            else
                printf("B");
        }
        printf("\n\n");
    }
    return 0;
}

stack(栈)

特点“先进后出
头文件:#include< stack >

1.相关操作
在这里插入图片描述
2.运用
在这里插入图片描述
方法一:

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;

int main()
{
    int n;
    char ch;
    scanf("%d",&n);
    getchar();
    while(n--)
    {
        stack<char>s;
        while(true)
        {
            ch=getchar();//一次读入一个字符
            if(ch==' '||ch=='\n'||ch=='\0')
            {
                while(!s.empty())
                {
                    printf("%c",s.top());//输出栈顶
                    s.pop();//清除栈顶
                }
                if(ch=='\n'||ch=='\0')
                    break;
                printf(" ");
            }
            else
            {
                s.push(ch);//入栈
            }
        }
        printf("\n");
    }
    return 0;
}

方法二:

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;

string str;
string s="";
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        getchar();
        while(n--)
        {
            getline(cin,str);//输入需要注意,因为输入的字符串有空格
            for(int i=0;i<str.length();i++)
            {
            //这里犯了个错误,就是把'\0'用成了'\n',使用'\n',会出现死循环
               while(str[i]!=' '&&str[i]!='\0')
               {
                   s+=str[i];
                   i++;
               }
               //翻转字符串
               reverse(s.begin(),s.end());
               cout<<s;
               s="";//重新初始化
               if(str[i]==' ')//最后一个字符串不需要输出空格
                  printf(" ");
            }
            printf("\n");
        }
    }
    return 0;
}

在这里插入图片描述

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;

int main()
{
    double n,m;
    char c;
    stack<double>s;
    while(~scanf("%lf",&n))
    {
        c=getchar();
        if(c=='\n'&&n==0)
            break;
        s.push(n);
        scanf("%c",&c);
        while(~scanf("%lf",&n))
        {
        //c等于*或者/的时候,先取出栈顶,再将后面一个数字与栈顶元素进行*或者/,
        //然后再入栈
            if(c=='*')
            {
                m=s.top();
                m*=n;
                s.pop();
                s.push(m);
            }
            if(c=='/')
            {
                m=s.top();
                m/=n;
                s.pop();
                s.push(m);
            }
            //+直接入栈
            if(c=='+')
            {
                s.push(n);
            }
            //-是将符号一起入栈,即将"负数"入栈
            if(c=='-')
            {
                s.push(0-n);
            }
            if(getchar()=='\n')
            {
                break;
            }
            c=getchar();
        }
        double sum=0;
        while(!s.empty())//判断栈是否为空
        {
            sum+=s.top();//取栈顶元素
            s.pop();//删除栈顶元素
        }
        printf("%.2lf\n",sum);
    }
    return 0;
}

queue(队列)

特点 “先进先出”
头文件:#include< queue>

1.相关操作
在这里插入图片描述
2.运用在这里插入图片描述

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;

string str,str1;
int main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        queue<int>q;
        stack<int>s;
        int m,temp;
        cin>>m>>str;
        for(int i=0;i<m;i++)
        {
            if(str=="FIFO")//队列
            {
                cin>>str1;
                if(str1=="IN")
                {
                    cin>>temp;
                    q.push(temp);//放进队列
                }
                if(str1=="OUT")
                {
                    if(q.empty())
                        printf("None\n");
                    else
                    {
                        printf("%d\n",q.front());//出队列
                        q.pop();
                    }
                }
            }
            else//栈
            {
                cin>>str1;
                if(str1=="IN")//入栈
                {
                    cin>>temp;
                    s.push(temp);
                }
                if(str1=="OUT")
                {
                    if(s.empty())
                        printf("None\n");
                    else
                    {
                        printf("%d\n",s.top());//出栈
                        s.pop();
                    }
                }
            }
        }
    }
    return 0;
}

priority_queue(优先队列)

以某种排序准则(默认为less)管理队列中的元素
头文件:#include< queue>
优先队列:优先级最高的先出队
队列和排序的完美结合,不仅可以存储数据,还可以将这些数据按照设定的规则进行排序。每次pushpop操作,优先队列都会动态调整,把优先级最高的元素放在前面。
priority_queue< int,vector< int>,less< int> >q; 完整的名称(从大到小)
priority_queue< int,vector< int>,greater< int>>q;(从小到大)
q.push(e) 根据元素的优先级将元素置入队列
q.top() 返回优先队列头部最大的元素的引用,但不移除
q. pop() 从栈中移除最大元素,但不返回
q.empty() 队列是否为空

//实现按照结构体中x,从大到小排序
/*struct node
{
    int x,y;
    bool operator < (const node&a)const
    {
        return x<a.x;
    }
};
priority_queue<node>q;
//node是一个结构体
//结构体里重载了'<'小于符号
*/
//样例
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;

struct node
{
    int x,y;
    bool operator < (const node&a)const
    {
        return x<a.x;
    }
}k;
priority_queue<node>q;//从大到小
//priority_queue<node,vector<node>,greater<node> >q;从小到大
int main()
{
    k.x=10,k.y=100;q.push(k);
    k.x=12,k.y=100;q.push(k);
    k.x=4,k.y=160;q.push(k);
    k.x=5,k.y=10;q.push(k);
    k.x=56,k.y=140;q.push(k);
    while(!q.empty())
    {
        node m=q.top();
        q.pop();
        printf("(%d %d)\n",m.x,m.y);
    }
    return 0;
}

在这里插入图片描述
2.运用
在这里插入图片描述

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;

struct node
{
    int b;//优先级
    int id;
    bool operator < (const node & t2)const
    {
        if(b!=t2.b)
            return b<t2.b;
        return id>t2.id;
    }
};
string str;
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        priority_queue<node>q[4];
        int id=1;
        node temp;
        for(int i=0;i<n;i++)
        {
            cin>>str;
            if(str=="IN")
            {
                int a,b;//a是看医生的序列,b是优先级
                scanf("%d %d",&a,&b);
                temp.b=b;
                temp.id=id;
                id++;
                q[a].push(temp);
            }
            else
            {
                if(str=="OUT")
                {
                    int a;
                    scanf("%d",&a);
                    if(q[a].empty())
                    {
                        printf("EMPTY\n");
                    }
                    else
                    {
                        printf("%d\n",q[a].top().id);
                        q[a].pop();
                    }
                }
            }
        }
    }
    return 0;
}

List(链表)

双向链表,它的内存空间不必连续,通过指针来进行数据的访问,高效率地在任意地方删除和插入,插入和删除操作是常数时间。
list和vector的优缺点正好相反,它们的应用场景不同:
1.vector:插入和删除操作少,随机访问元素频繁。
2.list:插入和删除频繁,随机访问较少。

1.迭代器

//所有容器都提供两种迭代器
1.container::iterator 以“读/写”模式遍历元素2.container::const_iterator 以“只读”模式遍历元素

//迭代器分类
1、双向迭代器
可以双向行进,以递增运算前进或以递减运算后退,可以用==和!=比较
list、set和map提供双向迭代器
2.随机存取迭代器
除了具备双向迭代器的所有属性,还具备随机访问能力。
可以对迭代器增加或减少一个偏移量,处理迭代器之间的距离或者使用<>之类的关系运算符比较两个迭代器。
vector、deque和string提供随机存取迭代器
stack、queue、priority_queue不支持迭代器

2.迭代器相关函数
在这里插入图片描述
3迭代器定义及使用

容器<类型>::iterator it;
//正序遍历
for(it=a.begin());a!=a.end();it++)
	cout<<*it<<endl;
//逆序遍历
for(it=a.rbegin();it!=rend();it++)
	cout<<*it<<endl;

4.运用
在这里插入图片描述

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;

int main()
{
    int t,n;
    cin>>t;
    while(t--)
    {
        cin>>n;
        int k=2;
        list<int> mylist;
        list<int>::iterator it;
        for(int i=1;i<=n;i++)
            mylist.push_back(i);
        while(mylist.size()>3)
        {
            int num=1;
            for(it=mylist.begin();it!=mylist.end();num++)
            {
                if(num%k==0)
                    it=mylist.erase(it);
                else
                    it++;
            }
            k==2?k=3:k=2;//1至2报数,1至3报数
        }
        for(it=mylist.begin();it!=mylist.end();it++)
        {
            if(it==mylist.begin())//格式处理,最后一个数据后面不能有空格
                cout<<*it;
            else
                cout<<" "<<*it;
           /* if(it!=mylist.begin())
                cout<<" ";
            cout<<*it;
            */
        }
        printf("\n");
    }
    return 0;
}

关联式容器

包括set、multiset、 map、multimap等。
set:集合,快速查找,不允许重复值
multiset:快速查找,允许重复值。
map:一对多映射,基于关键字快速查找,不允许重复值
multimap:一对多映射,基于关键字快速查找,允许重复值。

set(集合)

用二叉搜索树实现,集合中的每个元素只出现一次,且是排好序的。访问元素的时间复杂度是O(logn)的。

1.相关操作
在这里插入图片描述
2.运用
在这里插入图片描述

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;

ll a[1005];
set<ll>s;
set<ll>::iterator it;

int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        s.clear();
        for(int i=0;i<n;i++)
            cin>>a[i];
         //scanf("%l64d",&a[i]);使用这个在hdu上没有过
         //scanf("%lld",&a[i]);这个ac了
        for(int i=0;i<n;i++)
        {
            for(int j=i+1;j<n;j++)
            {
                s.insert(a[i]+a[j]);//元素一次相加
            }
        }
        ll sum=0;
        for(it=s.begin();it!=s.end();it++)
        {
            sum+=*it;
        }
        cout<<sum<<endl;
    }
    return 0;
}

Map

使用平衡二叉树管理元素。
元素包含两部分(key,value),key和value可以是任意类型。
头文件:#include< map>
根据元素的key自动对元素排序,因此根据元素的key进行定位很快,但根据元素的value定位很慢。
不能直接改变元素的key,可以铜鼓operator[]直接存取元素值。
map中不允许key相同的元素

count(key) 返回“键值等于key”的元素个数
find(key) 返回“键值等于key”的第一个元素,找不到返回end

1.Map赋值方法

第一种:用insert函数插入pair数据
map<int,string>stu;
stu.insert(pair<int,string>(1,"one"));
stu.insert(pair<int,string>(2,"two"));
stu.insert(pair<int,string>(3,"three"));
map<int,string>::iterator it;
for(it=stu.begin();it!=stu.end();it++)
	cout<<it->first<<" "<<it->second<<endl;

第二种:用数组方式插入数据
//Map[key]=value
stu[1]="one";
stu[2]="two";
stu[3]="three";

2.运用
在这里插入图片描述

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;

string str;
int main()
{
    int n,day,price;
    map<string,int>shop;
    while(cin>>n)
    {
        for(int i=1;i<=n;i++)
            cin>>str;//输入商店名字
        cin>>day;
        while(day--)
        {
            for(int i=1;i<=n;i++)
            {
                cin>>price>>str;
                shop[str]+=price;//用map直接操作商店,加上价格
            }
            int rank1=1;
            map<string,int>::iterator it;
            for(it=shop.begin();it!=shop.end();it++)
            {
                if(it->second>shop["memory"])//比较价格
                    rank1++;
            }
            cout<<rank1<<endl;
        }
        shop.clear();
    }
    return 0;
}

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值