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:不支持迭代器

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM