STL常用数据结构应用

各种使用函数可以看别的博客学习,这里重点讲应用

1.vector

  • []遍历,emplace_back,size,clear
  • sort(v.begin(),v.end());

应用:

特别是要开二维数组,要节省空间的时候而且长度不定的时候特别好用,图中的邻接表就是很好的例子。

邻接表中一维数组存储顶点,一维vector存储该顶点的所有邻接点,避免开二维数组(邻接矩阵)带来的空间浪费,稀疏图尤其好用。

有时题目要输出路径,可以建立个vector

uva101,木块问题,类似的。

写法:

vector<int>vex[maxn];


2.set

  • insert,erase(数据),count,clear

应用:输出不重复的、查找(logn因为内部是红黑树,即平衡二叉树)

uva11572

输入一个长度为n的序列A,找到一个尽量长的连续子序列,使得该序列中没有相同的元素。

#include<bits/stdc++.h>
using namespace std;
//插入count,,insert   erase
int a[100000005];

 
int main()
{
int T;
cin>>T;
int n;
while(T--)
{
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>a[i]; 
	} 
	set<int>temp;
	int l,r,ans;
	l=r=ans=0;
	while(r<n)//本来写l<n,多此一举
	{
		while(r<n&&!temp.count(a[r]))
		{
			temp.insert(a[r]);
			r++;
		}
		ans=max(ans,r-l);
		
		temp.erase(a[l]);
		l++;
	}
	cout<<ans<<endl;
}
}

3.map、multimap

  • [],insert,count和find函数,clear

应用:

①统计出现次数

以前统计字符出现次数,用的count[a[i]-'0'],其实就是用到map“关联数组”的思想。

#include<bits/stdc++.h>
#include<map>
using namespace std;
map<char,int>a;//常用string,int
int main()
{
char m[100];
cin>>m;
int max1=0;
for(int i=0;i<strlen(m);i++)
{
a[m[i]]++;//若不定义map用char数组,则要m[i]-'0'
max1=max(max1,a[m[i]]);//字符最多出现次数
}
cout<<max1<<endl;

 

}

还是上面的uva 11572

#include<bits/stdc++.h>
using namespace std;
//处理重复?→i,j   集合/出现次数 ==0→count[]++→ans→ --到!=temp 

map<int,int>a;
int count1[10000005];
int main()
{
	int T;
	cin>>T;
	int n;
	while(T--)
	{
		
		cin>>n;
		for(int i=0;i<n;i++)
		{
	
			cin>>a[i];
		}
		int temp=-1;
		int i,j,ans;
		i=j=ans=0;
		while(i<n)//尺取法
		{
			while(j<n&&count1[a[j]]==0)
			{
				count1[a[j]]++;
				j++;
				temp=a[j];
			}
			ans=max(ans,j-i);
			while(a[i]!=temp)
			{
				count1[a[i]]--;
				i++;
			}
			if(a[i]==temp)//刚好到重复数字的位置
			{
				count1[a[i]]--;
				i++;
			}
		}
		cout<<ans<<endl;
		
		a.clear();
	}

}

②分配“ID”判匹配,离散化

也是邻接表的例子,有时题目输入的是顶点名字而不是序号,《数据结构》课本给的方法是,另外用个string vex[]静态数组,但是每次都是顺序查找,要用O(n)时间,而map查找运用红黑树的原理,查找、插入、删除等操作仅用O(logn)时间。

pta QQ密码与账号的注册和登录

输入格式:

输入首先给出一个正整数N(≤),随后给出N行指令。每行指令的格式为:“命令符(空格)QQ号码(空格)密码”。其中命令符为“N”(代表New)时表示要新申请一个QQ号,后面是新帐户的号码和密码;命令符为“L”(代表Login)时表示是老帐户登陆,后面是登陆信息。QQ号码为一个不超过10位、但大于1000(据说QQ老总的号码是1001)的整数。密码为不小于6位、不超过16位、且不包含空格的字符串。

输出格式:

针对每条指令,给出相应的信息:

1)若新申请帐户成功,则输出“New: OK”;
2)若新申请的号码已经存在,则输出“ERROR: Exist”;
3)若老帐户登陆成功,则输出“Login: OK”;
4)若老帐户QQ号码不存在,则输出“ERROR: Not Exist”;
5)若老帐户密码错误,则输出“ERROR: Wrong PW”。

输入样例:

5
L 1234567890 [email protected]
N 1234567890 [email protected]
N 1234567890 [email protected]
L 1234567890 myQQ@qq
L 1234567890 [email protected]

输出样例:

ERROR: Not Exist
New: OK
ERROR: Exist
ERROR: Wrong PW
Login: OK
#include <bits/stdc++.h>
using namespace std;
map<string,int>p;//号码与0/1(是否存在)的联系 
map<string,string>q;//号码与密码的联系 
int main()
{
int n;
cin>>n;
char a;
string HM;
string MM;
	while(n--)
	{
	   	cin>>a>>HM>>MM;
	   	if(a=='N')
	   	{
	   		if(p[HM]==0)
	   		 {
	   		 	cout<<"New: OK"<<endl;
	   		 	p[HM]=1;
	   		 	q[HM]=MM;
			 }
			 else
			 {
			 	cout<<"ERROR: Exist"<<endl;
			 }
		}
		else
		{
			if(p[HM]==1)
			{
				if(q[HM]==MM)
				{
					cout<<"Login: OK"<<endl;
				}
				else
				{
					cout<<"ERROR: Wrong PW"<<endl;
				}
			}
			else
			{
				cout<<"ERROR: Not Exist"<<endl;
			}
		}
	}
}

4.queue,deque,stack

  • size(),front(top),pop(),push(),empty()
  • 定义                               queue<double> q;               deque<double> q;
    访问队列中的元素个数                q.size()                        q.size()
    判断队列空                         q.empty()                       q.empty() 
    尾部压入新元素                      q.push(x)                       q.push_back(x)
    头部压入新元素                      EOF                            q.push_front(x)
    弹出队列的第一个元素                 q.pop()                        q.pop_front()
    弹出队列的最后一个元素               EOF                            q.pop_back()
    访问队首元素                        q.front()                      (访问迭代器)q.begin()
    访问队尾元素                        q.back()                       (同上)q.end()
    删除所有元素                        EOF                            q.clear()
    删除任意位置x                       EOF                            q .erase(q.begin() + x)
    (某大佬总结)

应用:前者用的较多,如宽搜以及宽搜引出的各种算法。

deque有些滑动窗口类型题会用到

后者模拟题会用到,如括号匹配,但一般尽量用递归实现。

拓扑排序队列实现:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int maxn=1e6+10;
int n,m,t;
int G[1000][1000],id[1000],topo[1000];


void toposort()
{
    queue<int> q;
    int t=0;
    for(int i=1;i<=n;i++)
        if(id[i]==0)
            q.push(i);//入度为零的放进队列
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        topo[t++]=u;//入度为零的就是排好的,拿出来
        for(int i=1;i<=n;i++)//这个循环用来删除拿出来的点和相连接的点的边
            if(G[u][i]!=0)
                if(--id[i]==0)
                    q.push(i);
    }
    printf("%d",topo[0]);
    for(int i=1;i<t;i++)
        printf(" %d",topo[i]);
    printf("\n");
}


int main()
{
    while(scanf("%d%d",&n,&m) && (m!=0 || n!=0))
    {
        memset(G,0,sizeof(G));
        memset(id,0,sizeof(id));
        int a,b;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&a,&b);
            G[a][b]=1;
            id[b]++;//记录每个点的入度
        }
        toposort();
    }
    return 0;
}

5.priority_queue

注意取队首写法是top(),还有重载运算符写法。

应用:

①贪心:

之前说贪心前一般有排序操作,如果是静态取一般是直接sort,但有时变化是动态的,取出或修改一个元素可能会对整体顺序造成影响,需要时刻排序,这时用priority_queue。

poj 2431 3614 2010 pku 3253


②宽搜:

宽搜一般用queue,但在有些问题中搜索权值不同,导致搜索顺序有影响,用优先队列。

2018湘潭程序设计竞赛一道题,我的题解:

点击打开链接

6.list

  • splice

应用:线性结构(包括栈和队列)超时的时候,特别是合并操作,用链式结构往往有出其不意的效果。

zoj4016 Mergeable Stack

题意:对n个栈,有q次操作。每个操作可能为三种情况中的一种:1.将v插入到s栈的顶端;2.输出s栈的栈顶(若栈为空则输出empty);3.将栈t插入到栈s的栈顶。(合并)

 

#include<iostream>  
#include<cstdio>  
#include<cmath>  
#include<cstring>  
#include<cstdlib>  
#include<set>  
#include<vector>  
#include<stack>  
#include<map>  
#include<queue>  
#include<list>  
#include<algorithm>  
using namespace std;  
  
const int maxn=300005;  
list<int> l[maxn];  
  
int main()  
{  
    int n,q,t;  
    scanf("%d",&t);  
    while(t--)  
    {  
  
        scanf("%d%d",&n,&q);  
        for(int i=1; i<n+1; i++)l[i].clear();  
        while(q--)  
        {  
            int op;  
            scanf("%d",&op);  
            if(op==1)  
            {  
                int s,v;  
                scanf("%d%d",&s,&v);  
                l[s].push_back(v);  
            }  
            if(op==2)  
            {  
                int s;  
                scanf("%d",&s);  
                if(l[s].empty())puts("EMPTY");  
                else  
                {  
                    printf("%d\n",l[s].back());  
                    l[s].pop_back();  
                }  
            }  
            if(op==3)  
            {  
                int s,t;  
                scanf("%d%d",&s,&t);  
                l[s].splice(l[s].end(),l[t]);  
            }  
        }  
  
    }  
    return 0;  
  
}

猜你喜欢

转载自blog.csdn.net/zjyang12345/article/details/80361188