学习笔记(一)——STL

STL指的是C++的标准模板库(Standard Template Library),这玩意是把双刃剑,它集易用与复杂性于一身。以下是算法竞赛中几个常用模板的使用方法。

1.<algorithm>

这个头文件里集成了一些特定的算法函数,常用的有sort();find();swap();max/min();还有取容器中的最大最小值min_element(),max_element()

例程如下:

sort():

// sort algorithm example
#include <iostream>     // std::cout
#include <algorithm>    // std::sort
#include <vector>       // std::vector

bool myfunction (int i,int j) { return (i<j); }

struct myclass {
  bool operator() (int i,int j) { return (i<j);}
} myobject;

int main () {
  int myints[] = {32,71,12,45,26,80,53,33};
  std::vector<int> myvector (myints, myints+8);               // 32 71 12 45 26 80 53 33

  // using default comparison (operator <):
  std::sort (myvector.begin(), myvector.begin()+4);           //(12 32 45 71)26 80 53 33

  // using function as comp
  std::sort (myvector.begin()+4, myvector.end(), myfunction); // 12 32 45 71(26 33 53 80)

  // using object as comp
  std::sort (myvector.begin(), myvector.end(), myobject);     //(12 26 32 33 45 53 71 80)

  // print out content:
  std::cout << "myvector contains:";
  for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

swap():

// swap algorithm example (C++98)
#include <iostream>     // std::cout
#include <algorithm>    // std::swap
#include <vector>       // std::vector

int main () {

  int x=10, y=20;                              // x:10 y:20
  std::swap(x,y);                              // x:20 y:10

  std::vector<int> foo (4,x), bar (6,y);       // foo:4x20 bar:6x10
  std::swap(foo,bar);                          // foo:6x10 bar:4x20

  std::cout << "foo contains:";
  for (std::vector<int>::iterator it=foo.begin(); it!=foo.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

max():

// max example
#include <iostream>     // std::cout
#include <algorithm>    // std::max

int main () {
  std::cout << "max(1,2)==" << std::max(1,2) << '\n';
  std::cout << "max(2,1)==" << std::max(2,1) << '\n';
  std::cout << "max('a','z')==" << std::max('a','z') << '\n';
  std::cout << "max(3.14,2.73)==" << std::max(3.14,2.73) << '\n';
  return 0;
}

find():

// find example
#include <iostream>     // std::cout
#include <algorithm>    // std::find
#include <vector>       // std::vector

int main () {
  // using std::find with array and pointer:
  int myints[] = { 10, 20, 30, 40 };
  int * p;

  p = std::find (myints, myints+4, 30);
  if (p != myints+4)
    std::cout << "Element found in myints: " << *p << '\n';
  else
    std::cout << "Element not found in myints\n";

  // using std::find with vector and iterator:
  std::vector<int> myvector (myints,myints+4);
  std::vector<int>::iterator it;

  it = find (myvector.begin(), myvector.end(), 30);
  if (it != myvector.end())
    std::cout << "Element found in myvector: " << *it << '\n';
  else
    std::cout << "Element not found in myvector\n";

  return 0;
}

max/min_element():

#include <iostream>
#include <algorithm>
using namespace std;
bool myfn(int i, int j) { return i<j; }
int main () {
  int myints[] = {3,7,2,5,6,4,9};
  // using default comparison:
  cout << "The smallest element is " << *min_element(myints,myints+7) << endl;
  cout << "The largest element is " << *max_element(myints,myints+7) << endl;
  // using function myfn as comp:
  cout << "The smallest element is " << *min_element(myints,myints+7,myfn) << endl;
  cout << "The largest element is " << *max_element(myints,myints+7,myfn) << endl;
  return 0;
}

2.<vector>

vector一译作“矢量数组”,也有直观的翻译成“不定长数组”的翻译方法,没错,vector的本质就是一个不定长数组。不仅如此,它还把一些常用操作“封装”在了vector类型内部。如,a是一个vector,可以用a.size()来返回它的大小,a.resize()来改变他的大小,a.push_back()向尾部添加元素,a.pop_back()删除最后一个元素。

vector是一个模板类,所以需要用vector<int> a这样的方式来声明一个vector。某些时候,vector<int> a可以看作是一个int a[]这样的数组。vector看上去是数据类型中的“一等公民”,因为它们可以直接赋值,还可以作为函数的参数或者返回值,而不是像传递数组那样另外引用一个变量来指定元素个数。

vector的用法可以参考下面的问题,由于题干过长此处只放链接:

UVa101 The Blocks Problem

例程:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>

#define file
#define PI 3.1415926
#define MAX(A,B) ((A)>(B)?(A):(B))
#define MIN(A,B) ((A)<(B)?(A):(B))
#define LL long long
#define fordo(A,B,C) for(int (A)=(B);(A)<(C);(A)++)
using namespace std;

const int maxn=30;
int n;
vector<int> pile[maxn];//每个pile[i]都是一个vector

//找木块a所在的pile和height,以引用的形式返回调用者
void find_block(int a,int &p,int &h)
{
    for(p=0;p<n;p++)
    {
        for(h=0;h<pile[p].size();h++)
        {
            if(pile[p][h]==a)
                return;
        }
    }
}

//把第P堆高度为h的木块上方所有木块移回原位置
void clear_above(int p,int h)
{
    for(int i=h+1;i<pile[p].size();i++)
    //fordo(i,h+1,pile[p].size())
    {
        int b=pile[p][i];
        pile[b].push_back(b);//把木块b放回原位置
    }
    pile[p].resize(h+1);//pile只保留下标0~h的元素
}

//把第p堆的高度为h及其上方的木块整体移动到p2堆顶部
void pile_onto(int p,int h,int p2)
{
    for(int i=h;i<pile[p].size();i++)
    //fordo(i,h,pile[p].size())
    {
        pile[p2].push_back(pile[p][i]);
    }
    pile[p].resize(h);
}

void print()
{
    //fordo(i,0,n)
    for(int i=0;i<n;i++)
    {
        printf("%d:",i);
        for(int j=0;j<=pile[i].size();j++)
        //fordo(j,0,pile[i].size())
            printf(" %d",pile[i][j]);
        printf("\n");
    }
}
int main()
{

    #ifdef file
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
    #endif // file
    int a,b;
    cin>>n;
    string s1,s2;
    fordo(i,0,n)
        pile[i].push_back(i);
    while(cin>>s1>>a>>s2>>b)
    {
        int pa,pb,ha,hb;
        find_block(a,pa,ha);
        find_block(b,pb,hb);
        if(pa==pb)
            continue;
        if(s2=="onto")
            clear_above(pb,hb);
        if(s1=="move")
            clear_above(pa,ha);
        pile_onto(pa,ha,pb);
    }
    print;
    return 0;
}

3.<set>

集合与映射也是两个常用的容器,set就是数学上的集合——每个元素最多只出现一次。和sort一样,自定义类型也可以构建set,但同样必须定义“小于”运算符才行。本质上,set容器内部采用红黑树的平衡二叉检索树的数据结构,在插入元素时,它会自动调整二叉树的排列,把该元素放到合适的位置,以确保每个子树根结点的值都大于左子树所有节点的值,而小于右子树所有节点的值;另外,还保证根节点左子树和右子树的高度相等,这样,整个二叉树高度最小,检索速度也是最快的。

平衡二叉树的检索算法采用中序遍历法,检索效率是高于vector、deque、&list等容器。另外,采取中序遍历算法的好处是,可以将键值从小到大遍历出来。换句话来说,构造set容器的目的就是为了快速检索。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>

//#define file
#define PI 3.1415926
#define MAX(A,B) ((A)>(B)?(A):(B))
#define MIN(A,B) ((A)<(B)?(A):(B))
#define LL long long
#define fordo(A,B,C) for(int (A)=(B);(A)<(C);(A)++)
using namespace std;

int main()
{

    #ifdef file
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
    #endif // file
    set<int> s;
    for(int i=1;i<=10;i++)//向set容器s中插入键值
        s.insert(i);
    set<int>::iterator it;//定义迭代器it
    for(it=s.begin();it!=s.end();it++)
        cout<<*it<<" ";//中序遍历集合中所有元素
    cout<<endl;

    set<int>::reverse_iterator rit;//定义反向迭代器rit
    for(rit=s.rbegin();rit!=s.rend();rit++)
        cout<<*rit<<" ";//反向遍历集合中所有元素
    cout<<endl;

    s.erase(6);//删除容器中的6这一键值
    for(it=s.begin();it!=s.end();it++)
        cout<<*it<<" ";//中序遍历集合中所有元素
    cout<<endl;

    it=s.find(3);
    //find对集合元素进行查找,找到则会返回该键值的位置,没找到则返回end()
    if(it!=s.end())
        cout<<*it<<endl;
    else
        cout<<"not find it"<<endl;

    s.clear();//清空容器
    cout<<s.size()<<endl;
    return 0;
}
multiset与set有异曲同工之处,区别在于multiset允许存在重复元素,此处不再赘述。

4.<map>

map直译为映射容器,该容器的元素数据是由一个键值和一个映照数据组成的,键值与数据之间有一一映照的关系。
我们可以用一个map<string,int>month_name来实现月份名到月数的映射,然后用month_name["JULY"]=7这样的方式赋值。

与set容器一样,map内部也是使用了红黑树来实现的。插入元素的键值不允许重复,比较函数只对元素的键值进行比较。因此set和map的用法有点类似。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>

//#define file
#define PI 3.1415926
#define MAX(A,B) ((A)>(B)?(A):(B))
#define MIN(A,B) ((A)<(B)?(A):(B))
#define LL long long
#define fordo(A,B,C) for(int (A)=(B);(A)<(C);(A)++)
using namespace std;

int main()
{

    #ifdef file
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
    #endif // file
    map<string,float> m;
    m["jack"]=98.0;
    m["bomi"]=96.0;
    m["kate"]=97.5;
    
    map<string,float>::iterator it;
    for(it=m.begin();it!=m.end();it++)
    {
        cout<<(*it).first<<" : "<<(*it).second<<endl;
    }//中序遍历容器并输出
    cout<<endl;

    it=m.find("jack");
    cout<<(*it).first<<" : "<<(*it).second<<endl;
    cout<<endl;//查找元素

    m.erase("jack");
    for(it=m.begin();it!=m.end();it++)
    {
        cout<<(*it).first<<" : "<<(*it).second<<endl;
    }//删除元素
    cout<<endl;
    return 0;
}

利用map可以方便的实现数字分离、数字映射字符等应用,此处不提供例程。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值