STL的一些数据结构(转自chunlvxiong)
本文默认#include <bits/stdc++.h>,默认using namesapce std。
一、vector
vector相当于一个动态的数组。
1、定义:vector <int> a--这样a的存储数据类型为int,你也可以定义一个结构体,例如vector <node> a。
2、清空:a.clear()
3、判断是否空:a.empty()--如果空返回1,否则返回0
4、元素个数:a.size()--注意实际存储区间是0..a.size()-1
5、读取元素:a[i]--vector存储区间连续,因此可以直接读取。
6、尾部插入元素b:a.push_back(b)--复杂度O(1)。
7、尾部删除元素:a.push_pop()--复杂度O(1)。
8、返回开头元素的位置:a.begin()
9、返回末尾元素的后一个位置:a.end()
10、删除元素:a.erase() 例如:a.erase(a.begin()+3)--删除第4个元素
复杂度与元素在序列中的位置有关,元素位置越往后这个操作越快,如果删除开头元素复杂度为O(N)。
对比:
下面这是一个用于建边的数组模拟链表。
#include <bits/stdc++.h>
using namespace std;
const int maxm=10005;
const int maxn=10005;
struct node{
int to,len,next;
}edge[maxm];
int m,head[maxn],tot;
void init(){
memset(head,0,sizeof(head)),tot=0;
}
void makedge(int u,int v,int t){
edge[++tot].to=v;
edge[tot].len=t;
edge[tot].next=head[u];
head[u]=tot;
}
int main(){
scanf("%d",&m),init();
for (int i=1,u,v,t;i<=m;i++){
scanf("%d%d%d",&u,&v,&t);
makedge(u,v,t);
}
return 0;
}
下面是用vector实现的程序。
#include <bits/stdc++.h>
using namespace std;
const int maxn=10005;
struct node{
int to,len;
};
int m;
vector<node>edge[maxn];
void init(){
for (int i=1;i<=maxn;i++) edge[i].clear();
}
int main(){
scanf("%d",&m),init();
for (int i=1,u,v,t;i<=m;i++){
scanf("%d%d%d",&u,&v,&t);
edge[u].push_back(node{v,t});
}
return 0;
}
二、map
map是一种关联容器,它能建立key-value的对应关系。
1、定义:例如map <string,int> a,定义一个key为string类型,value为int类型(一般这样可以完成字符串Hash的功能)。
2、清空:a.clear()
3、判断是否空:a.empty()--如果空返回1,否则返回0
4、元素个数:a.size()--注意实际存储区间为0..a.size()-1
5、插入元素:a["stjfsijf"]=5--即认为key为stjfsijf的value被修改为5--复杂度带log
6、读取元素:a["……"]--类似数组方式直接读取即可。
对比:
下面是一个字符串hash的程序。
#include <bits/stdc++.h>
using namespace std;
int n,size;
char s[1005],name[1005][1005];
int find(char s[]){
for (int i=1;i<=size;i++)
if (strcmp(s,name[i])==0)
return i;
strcpy(name[++size],s);
return size;
}
int main(){
size=0;
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%s",&s);
printf("%d\n",find(s));
}
return 0;
}
然后下面是用map实现的程序。
#include <bits/stdc++.h>
using namespace std;
map <string,int> name;
int n;
string s;
int main(){
name.clear();
scanf("%d",&n);
for (int i=1,cnt=0;i<=n;i++){
cin>>s;
if (name[s]==0) name[s]=++cnt;
printf("%d\n",name[s]);
}
return 0;
}
三、set
set是一种集合容器,它的用途在于高效检索。
1、定义:set <int> a--这样a的存储数据类型为int,你也可以定义一个结构体,例如set <node> a。
2、清空:a.clear()
3、判断是否空:a.empty()--如果空返回1,否则返回0
4、元素个数:a.size()--注意实际存储区间为0..a.size()-1
5、插入值为b的元素:a.insert(b)--复杂度带log,但要注意相同的值只会保留最前面的一个。
6、删除值为b的元素:a.erase(b)--复杂度带log。
7、返回开头元素的位置:a.begin()
8、返回末尾元素的后一个位置:a.end()
9、查找元素:a.find(b)--复杂度带log,找到返回该元素迭代器的位置,如果找不到返回a.end()。
10、a.lower_bound(b)--返回第一个大于等于b的元素迭代器的位置,如果找不到返回a.end()(复杂度带log)
11、a.upper_bound(b)--返回第一个大于b的元素迭代器的位置,如果找不到返回a.end()(复杂度带log)
实例:
下面通过一个具体程序来说明set的用法。
#include <bits/stdc++.h>
using namespace std;
struct node{
int x,y;
friend operator <(node a,node b){
return a.x<b.x;
}
};
set <node> a;
set <node>::iterator id;
int n,q;
int main(){
a.clear();
scanf("%d",&n);
for (int i=1,x,y;i<=n;i++){
scanf("%d%d",&x,&y);
if (a.find(node{x,0})!=a.end()) a.erase(node{x,0});
a.insert(node{x,y});
}
scanf("%d",&q);
for (int i=1,x;i<=q;i++){
scanf("%d",&x);
id=a.find(node{x,0});
if (id==a.end()) puts("-1");
else printf("%d\n",(*id).y);
}
return 0;
}
/*
程序要求:输入n个key-value(均为int类型),要求使用set维护。
如果有相同的数在,将value改为后一个。
接下来有q个询问,每个询问一个数,如果它存在,那么输出它的value。
如果不存在,输出-1。
*/
四、priority_queue
priority_queue是优先队列,也就是堆。
1、定义:priority_queue <int> a--这样a的存储数据类型为int,你也可以定义一个结构体,例如priority_queue <node> a。
2、入堆:a.push(b)--复杂度带log
3、堆顶元素出堆:a.pop()--复杂度带log
4、判断是否空:a.empty()--如果空返回1,否则返回0
5、元素个数:a.size()--注意实际存储区间为0..a.size()-1
6、取出堆顶元素:a.top()
对比:
下面给出堆排(降序)的程序。
#include <bits/stdc++.h>
using namespace std;
const int maxn=105;
int n,heap_volume,heap[maxn];
void push(int x){
int i=++heap_volume;
while (i>1 && x>heap[i>>1]){
heap[i]=heap[i>>1];
i>>=1;
}
heap[i]=x;
}
void pop(){
int x=heap[heap_volume--],i=1,j;
while (i<=heap_volume){
j=i<<1;
if (j+1<=heap_volume && heap[j+1]>heap[j]) j++;
if (j<=heap_volume && heap[j]>x){
heap[i]=heap[j];
i=j;
}
else{
heap[i]=x;
break;
}
}
}
int main(){
scanf("%d",&n);
heap_volume=0;
for (int i=1,x;i<=n;i++)
scanf("%d",&x),push(x);
for (int i=1;i<=n;i++)
printf("%d ",heap[1]),pop();
return 0;
}
下面给出使用priority_queue之后的堆排。
#include <bits/stdc++.h>
using namespace std;
int n;
priority_queue <int> heap;
int main(){
scanf("%d",&n);
for (int i=1,x;i<=n;i++)
scanf("%d",&x),heap.push(x);
for (int i=1;i<=n;i++)
printf("%d ",heap.top()),heap.pop();
return 0;
}
五、list
list即双向链表,跟vector很像,不同之处在于其中间修改元素较快但不支持随机访问元素。
1、定义:list <int> a--这样a的存储数据类型为int,你也可以定义一个结构体,例如list <node> a。
2、清空:a.clear()
3、判断是否空:a.empty()--如果空返回1,否则返回0
4、元素个数:a.size()--注意实际存储区间为0..a.size()-1
5、插入元素:
尾部:a.push_back(b)--复杂度O(1)
头部:a.push_front(b)--复杂度O(1)
6、返回开头元素的位置:a.begin()
7、返回末尾元素的后一个位置:a.end()
8、删除元素:
尾部:a.pop_back()--复杂度O(1)
头部:a.pop_front()--复杂度O(1)
a.erase()--注意此时你不能使用a.erase(a.begin()+3)来删除第4个元素,因为list不是vector,占用连续的内存空间。
9、排序:a.sort(cmp)--你可以自己写比较函数
实例:
下面用一个程序来具体说明list的用法。
#include <bits/stdc++.h>
using namespace std;
list <int> a;
list <int>::iterator id;
bool cmp(int a,int b){
return a>b;
}
int main(){
int x;
while (~scanf("%d",&x)){
a.push_back(x);
if (a.size()>10) a.pop_front();
}
a.sort(cmp);
id=a.begin();
for (id=a.begin();id!=a.end();id++)
printf("%d\n",(*id));
return 0;
}
/*
程序说明:输入一些元素加入到list中,若元素个数超过10个,那么删掉表头元素。
最后降序输出所有元素。
*/
六、deque
deque,双端队列。
1、定义:deque <int> a--这样a的存储数据类型为int,你也可以定义一个结构体,例如deque <node> a。
2、清空:a.clear()
3、判断是否空:a.empty()--如果空返回1,否则返回0
4、元素个数:a.size()--注意实际存储区间为0..a.size()-1
5、插入元素:
尾部:a.push_back(b)--复杂度O(1)
头部:a.push_front(b)--复杂度O(1)
6、返回开头元素的位置:a.begin()
7、返回末尾元素的后一个位置:a.end()
8、删除元素:
尾部:a.pop_back()--复杂度O(1)
头部:a.pop_front()--复杂度O(1)
9、删除元素:a.erase() 例如:a.erase(a.begin()+3)--删除第4个元素
这个东西复杂度与元素位置有关,如果元素位置靠近头部或是尾部那么会比较快,但是如果元素位置在中间那么复杂度是O(N)的。
10、读取元素:a[i]
实例:
#include <bits/stdc++.h>
using namespace std;
deque <int> a;
int n;
int main(){
a.clear();
scanf("%d",&n);
for (int i=1,x,y;i<=n;i++){
scanf("%d%d",&x,&y);
if (y) a.push_back(x);
else a.push_front(x);
}
while (!a.empty())
printf("%d\n",a[0]),a.pop_front();
return 0;
}
/*
程序说明:输入n个数,并给出其插入方式(1表末尾插入,0表头部插入)
最后要求输出最终序列。
*/
七、stack/queue
这两个东西谁都不会陌生,一个是栈,另一个是队列。
1、定义:stack<int>a或是queue<int>a,支持结构体,例如:stack<node>a或是queue<node>a。
2、元素个数:a.size()--注意实际存储区间为0..a.size()-1
3、判断是否空:a.empty()--如果空返回1,否则返回0
4、入队/入栈:a.push(x)
出队/出栈:a.pop()
5、访问栈顶/队头元素:
stack:a.top()
queue:a.front()
其实个人觉得这两个东西还不如自己写了算了。
八、iterator
迭代器,很多数据结构都要用到的东西。
1、定义:以vector为例:vector<int>::iterator a
2、双向:a++,a-- 前后置迭代器
3、输出:(*a)或(*a).val
4、随机:a+=p,a-=p 前后移动迭代器p位
也支持引用a+p,a-p。
5、赋值:a=b
6、比较:a==b或a!=b判断两个迭代器是否相同
对于随机迭代器,还可以通过<,>,<=,>=等符号来判断位置关系。
下面给出上述数据结构的迭代器类型:
vector:随机迭代器
map:双向迭代器
set:双向迭代器
priority_queue:不支持迭代器
list:双向迭代器
deque:随机迭代器
stack/queue:不支持迭代器


浙公网安备 33010602011771号