tkdsheep-STL

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

写这个页面主要是帮我的两只队友熟悉一下竞赛里常用的STL,欢迎各位学长补充编辑以及指出其中的错误和不足之处


直接切入主题,不废话了


=== queue ===

http://www.cplusplus.com/reference/stl/queue/

queue就是普通的队列,队列声明方式: queue <元素类型> 变量名

比如 queue <int> q; 表示你声明了一个队列q,队列里的元素是int类型的

queue用的最多的地方就是bfs,在我的代码习惯里,一个大致的bfs框架是这样写的:

queue <node> q; //node代表一个结构体,如果是简单的格子bfs题,那么node里面一般有表示位置的两个int变量x,y,以及走的步数step

while(!q.empty())//队列非空

{
    node ss=q.front();//得到队首的元素

    q.pop();//抛出队首的元素 

    /*进行更新操作得到新的状态tt*/

    q.push(tt);//将新的状态压入队列中 
}

从上面的例子可以看出queue应该是非常简单易用,front()函数得到队首元素,pop()和push()分别代表出队和入队

为什么要用queue?因为不容易出错,不用自己手动维护front、tail之类的指针,队列的空间也是动态分配的,不用担心数组开小了越界之类的问题

=== priority_queue ===

http://www.cplusplus.com/reference/stl/priority_queue/

priority_queue是优先队列,里面包含的函数跟queue基本一样,除了获得队首元素是top()不是front()

优先队列是我用得非常多的一个STL,它可以实现最大堆或者最小堆,只要我们手动定义好堆里面的元素比较的规则

priority_queue默认是最大堆,比如定义一个priority_queue <int> q,那么每次调用q.top()得到的都是队列里最大的一个int值

但如果优先队列里的元素是自定义的结构体,比如priority_queue <node> q; 那么必须重载运算符使编译器知道node元素是如何比较大小关系的

举个例子,假设我定义了这样的node

struct node
{
    int x,y;
}

由于node里面有两个元素,x和y,所以编译器不知道到底怎样才能比较两个node的大小关系

假设我们希望优先队列抛出的队首元素是队列里x值最小的node,如果有多个最小x,则取y最小的

那么就要在node里写一个小于号运算符重载,如下所示

{{{

struct node
{
    int x,y;
    friend bool operator < (node n1,node n2)//重载小于号
    {
        if(n1.x != n2.x)//如果x不相等则按x比较大小
            return n1.x > n2.x; //注意这里,我重载的是小于号,返回的却是大于号,因为优先队列默认是最大堆,而这里实际上是小的值优先,所以要“反”一下
        else return n1.y > n2.y;//如果x相等则按y比较大小
    }
}

}}}

summer2012题库里可以用queue以及priority_queue的题目比较多,比如第一轮的0013 Battle: Dojo 0024 Toy Blocks 以及后面的0046 LF2 

=== vector ===

'''不会做题写点东西,肥羊学长见谅...请随意删改._.'''

就实际上来说,vector是竞赛中使用STL最多的一个部分,合理的使用vector可以极大地提高代码速度、减少编程复杂度及代码长度,是应当首先掌握的东西。

vector类似于一个动态的数组,它的各种用法与其他STL的用法都很相像,如果熟练掌握vector的用法对掌握其他STL的用法很有好处。

使用前记得在头文件上加入{{{ #include <vector> }}}。

vector的定义类似{{{ vector<ELEMENT TYPE> <NAME> }}},例如定义一个名为gao的int的vector就是{{{ vector<int> gao }}}。

主要的用法有:
 * push_back(<ELEMENT>):将一个元素插入到vector的尾部。
 * clear():清空vector。'''非常重要,因为多组数据必须使用这个保证环境是干净的。'''
 * begin(), end():开头与末尾的iterator。iterator我建议肥羊学长专门再开个章节讲…… 相对应的还有反向迭代器rbegin(), rend()。
 * size():vector的大小,类似数组大小。'''非常常用,尤其在循环中。'''

例如存图,就经常使用这样的写法:
{{{
for(int i = 0; i < M; ++i){
    scanf("%d%d%d", &x, &y, &w);
    Gr[x].push_back(make_pair(y, w));
}
}}}

遍历时就可以:
{{{
for(int i = 0; i < N; ++i){
    for(int j = 0; j < Gr[i].size(); ++j)
      Dfs(Gr[i][j]);
}
}}}

相匹配的一些常用的算法操作:
 * sort(gao.begin(), gao.end()):排序。
 * lower_bound(gao.begin(), gao.end(), <ELEMENT>):返回不小于<ELEMENT>的迭代器。这个是算法库导出来的,要保证vector有序才能够使用。

{{{
仰慕搞学长~写的挺详细了丫~我再补充一个就是vector可以像数组一样直接使用,比如vector <int> L

那么L[0]就是第1个元素,L[i]就是第i+1个元素,当然要保证i<L.size(),不然会段错误,总之vector是相当方便易用拉
}}}


=== set ===
set有两个非常重要也非常有用的性质:

1.set可以看做一个集合,集合里面的每一个元素都是唯一的,任意两个元素都不会相同

2.set里面的元素永远是有序的,因此可以实现log级别的查找、添加和删除操作

举个例子

set <int> st;//声明一个存放int类型元素的set,变量名叫st,

set的查找、添加、删除操作需要用到“迭代器”,迭代器有点类似指针吧

set <int> ::iterator it;//声明一个对应类型的迭代器,变量名叫it

插入操作: st.insert(5); 如果st里面已经有5了,那么这个操作不会对st产生任何改变

查找操作:  it=st.find(5);  如果st里面没有元素5,则it==st.end(),如果有5,那么*it==5

删除操作:  st.erase(it);  注意这里必须保证it!=st.end()

遍历整个set: for(it=st.begin();it!=st.end();it++)  每次取*it即为当前遍历到的元素,这样遍历出来的元素一定是从小到大的

lower_bound函数:  it=st.lower_bound(5) 在st中找到【第一个大于等于】5的元素的迭代器位置,找不到则返回st.end()

upper_bound函数:  it=st.upper_bound(5) 在st中找到【第一个大于】5的元素的迭代器位置,找不到则返回st.end()

clear()函数:清空整个set,这个在全局set每次初始化的时候不要忘记

size()函数:返回当前set里的元素个数

用到set()的例题可以参加搞学长的0105 Irotoridori no Sekai,基本上set的所有操作都用到了


=== map ===

=== string ===

=== sort ===

写这个页面主要是帮我的两只队友熟悉一下竞赛里常用的STL,欢迎各位学长补充编辑以及指出其中的错误和不足之处

直接切入主题,不废话了

queue

http://www.cplusplus.com/reference/stl/queue/

queue就是普通的队列,队列声明方式: queue <元素类型> 变量名

比如 queue q; 表示你声明了一个队列q,队列里的元素是int类型的

queue用的最多的地方就是bfs,在我的代码习惯里,一个大致的bfs框架是这样写的:

queue q; //node代表一个结构体,如果是简单的格子bfs题,那么node里面一般有表示位置的两个int变量x,y,以及走的步数step

while(!q.empty())//队列非空

{

node ss=q.front();//得到队首的元素

q.pop();//抛出队首的元素

/*进行更新操作得到新的状态tt*/

q.push(tt);//将新的状态压入队列中

}

从上面的例子可以看出queue应该是非常简单易用,front()函数得到队首元素,pop()和push()分别代表出队和入队

为什么要用queue?因为不容易出错,不用自己手动维护front、tail之类的指针,队列的空间也是动态分配的,不用担心数组开小了越界之类的问题

priority_queue

http://www.cplusplus.com/reference/stl/priority_queue/

priority_queue是优先队列,里面包含的函数跟queue基本一样,除了获得队首元素是top()不是front()

优先队列是我用得非常多的一个STL,它可以实现最大堆或者最小堆,只要我们手动定义好堆里面的元素比较的规则

priority_queue默认是最大堆,比如定义一个priority_queue q,那么每次调用q.top()得到的都是队列里最大的一个int值

但如果优先队列里的元素是自定义的结构体,比如priority_queue q; 那么必须重载运算符使编译器知道node元素是如何比较大小关系的

举个例子,假设我定义了这样的node

struct node

{

int x,y;

}

由于node里面有两个元素,x和y,所以编译器不知道到底怎样才能比较两个node的大小关系

假设我们希望优先队列抛出的队首元素是队列里x值最小的node,如果有多个最小x,则取y最小的

那么就要在node里写一个小于号运算符重载,如下所示

struct node
{
    int x,y;
    friend bool operator < (node n1,node n2)//重载小于号
    {
        if(n1.x != n2.x)//如果x不相等则按x比较大小
            return n1.x > n2.x; //注意这里,我重载的是小于号,返回的却是大于号,因为优先队列默认是最大堆,而这里实际上是小的值优先,所以要“反”一下
        else return n1.y > n2.y;//如果x相等则按y比较大小
    }
}

summer2012题库里可以用queue以及priority_queue的题目比较多,比如第一轮的0013 Battle: Dojo 0024 Toy Blocks 以及后面的0046 LF2

vector

不会做题写点东西,肥羊学长见谅...请随意删改._.

就实际上来说,vector是竞赛中使用STL最多的一个部分,合理的使用vector可以极大地提高代码速度、减少编程复杂度及代码长度,是应当首先掌握的东西。

vector类似于一个动态的数组,它的各种用法与其他STL的用法都很相像,如果熟练掌握vector的用法对掌握其他STL的用法很有好处。

使用前记得在头文件上加入 #include

vector的定义类似 vector ,例如定义一个名为gao的int的vector就是 vector gao

主要的用法有:

  • push_back():将一个元素插入到vector的尾部。
  • clear():清空vector。非常重要,因为多组数据必须使用这个保证环境是干净的。
  • begin(), end():开头与末尾的iterator。iterator我建议肥羊学长专门再开个章节讲…… 相对应的还有反向迭代器rbegin(), rend()。
  • size():vector的大小,类似数组大小。非常常用,尤其在循环中。

例如存图,就经常使用这样的写法:

for(int i = 0; i < M; ++i){
    scanf("%d%d%d", &x, &y, &w);
    Gr[x].push_back(make_pair(y, w));
}

遍历时就可以:

for(int i = 0; i < N; ++i){
    for(int j = 0; j < Gr[i].size(); ++j)
      Dfs(Gr[i][j]);
}

相匹配的一些常用的算法操作:

  • sort(gao.begin(), gao.end()):排序。
  • lower_bound(gao.begin(), gao.end(), ):返回不小于的迭代器。这个是算法库导出来的,要保证vector有序才能够使用。
仰慕搞学长~写的挺详细了丫~我再补充一个就是vector可以像数组一样直接使用,比如vector <int> L
那么L[0]就是第1个元素,L[i]就是第i+1个元素,当然要保证i<L.size(),不然会段错误,总之vector是相当方便易用拉

set

set有两个非常重要也非常有用的性质:

1.set可以看做一个集合,集合里面的每一个元素都是唯一的,任意两个元素都不会相同

2.set里面的元素永远是有序的,因此可以实现log级别的查找、添加和删除操作

举个例子

set st;//声明一个存放int类型元素的set,变量名叫st,

set的查找、添加、删除操作需要用到“迭代器”,迭代器有点类似指针吧

set ::iterator it;//声明一个对应类型的迭代器,变量名叫it

插入操作: st.insert(5); 如果st里面已经有5了,那么这个操作不会对st产生任何改变

查找操作: it=st.find(5); 如果st里面没有元素5,则it==st.end(),如果有5,那么*it==5

删除操作: st.erase(it); 注意这里必须保证it!=st.end()

遍历整个set: for(it=st.begin();it!=st.end();it++) 每次取*it即为当前遍历到的元素,这样遍历出来的元素一定是从小到大的

lower_bound函数: it=st.lower_bound(5) 在st中找到【第一个大于等于】5的元素的迭代器位置,找不到则返回st.end()

upper_bound函数: it=st.upper_bound(5) 在st中找到【第一个大于】5的元素的迭代器位置,找不到则返回st.end()

clear()函数:清空整个set,这个在全局set每次初始化的时候不要忘记

size()函数:返回当前set里的元素个数

用到set()的例题可以参加搞学长的0105 Irotoridori no Sekai,基本上set的所有操作都用到了

map

string

sort