STL containers

目录

一、概述

  • STL是什么
  • 为什么需要学习STL
  • 初识STL
  • STL的组成

二、容器

三、算法

 


 概述

1.1 STL是什么
      STL是C++程序设计者不可忽视的技术,全称为Standard Template Library (STL),中文名为标准模板库,更准确的说C++程序设计语言标准模板库。STL是所有C++编译器和所有操作系统平台都支持的一种库,也就是说所有的编译器提供给C++程序设计者的接口都是一样的,即虽然顶层实现可以是不同,但是运行结构都是相同的。目前,STL是C++的一部分,被内建在编译器之内。
 
1.2 为什么需要学习STL
     STL模板具有一些优点:第一,STL是 C++的ANSI/ISO 标准的一部分,可以用于所有C++语言编译器和所有平台,如Windows,Unix和Linux等;第二,提供了大量的可复用软件组织,比如排序、搜索算法等;第三,使用STL编写的代码更容易修改和阅读。虽然使用方便,但是内部实现很复杂。但不管如何,STL是每个C++程序设计者迟早都要啃的一块骨头。
 
1.3  初识STL
     下面代码来认识STL:
1 #include <iostream>
2 int main(void){
3     double a[] = {1, 2, 3, 4, 5};
4     std::cout<<mean(a, 5)<<std::endl;    // will print 3
5     return 0;
6 }

除了那个std有点让人不舒服以外,这是一段普通的没有使用STL的C++代码。再来看下一段,

 1 #include <vector>
 2 #include <iostream>
 3 int main(){
 4     std::vector<double> a;
 5     a.push_back(1);
 6     a.push_back(2);
 7     a.push_back(3);
 8     a.push_back(4);
 9     a.push_back(5);
10     for(int i = 0; i < a.size(); ++i){
11         std::cout<<a[i]<<std::endl;
12     }
13     return 0;
14 }

      如果你真的没有接触过STL的话,你会问,呀,vector 是啥呀?这是一段纯种的STL代码,看到尖括号<double>了吧,知道那是模板了吧。看到a.push_back(5)、a.size()你不感觉奇怪么?可是我们并没有定义这些函数啊。再继续看下面的代码

 1 #include <vector>
 2 #include <iostream>
 3 int main(){
 4     std::vector< int > q;
 5     q.push_back(10);
 6     q.push_back(11);
 7     q.push_back(12);
 8     std::vector< int > v;
 9     for(int i=0; i<5; ++i){
10         v.push_back(i);
11     }
12     std::vector<int>::iterator it = v.begin() + 1;
13     it = v.insert(it, 33);
14     v.insert(it, q.begin(), q.end());
15     it = v.begin() + 3;
16     v.insert(it, 3, -1);
17     it = v.begin() + 4;
18     v.erase(it);
19     it = v.begin() + 1;
20     v.erase(it, it + 4);
21     v.clear();
22     return 0;
23 }

      这一段你又看到了新东西了吧:iterator、insert、erase、clear。关于模板的其他细节,读者可以参阅《C++ Templates 中文版》。在这里,仅简单地介绍一下模板类和函数模板的概念。模板是C++中实现代码重用机制的一种工具,可以实现类型参数化,把类型定义为参数。函数模板和类模板允许用户构造模板函数和模板类。下面再来看一段函数模板的例子:

 1 #include<iostream>
 2 #include<string>
 3 using namespace std;
 4 //定义函数模板
 5 template<class T>   //template 是关键字,T 表示一种待实例化的类型
 6                             //template<typename T>  也是对的
 7 T MAX(T a, T b){    //函数模板,函数名为 max,此函数有2个T类型的参数,返回类型为T
 8     return (a>b)?a:b; 
 9 }
10 
11 //在此例实例化的时候,T可以是多种类型的,int,char,string…
12 int main(){
13     int x=2,y=6;
14     double x1=9.123,y1=12.6543;
15     cout<<"把T实例化为int:"<<MAX(x,y)<<endl;        //实例化函数模板,把T实例化为int
16     cout<<"把T实例化为double:"<<MAX(x1,y1)<<endl;    //把T实例化为double
17 }

注意:在此例实例化的时候,可以是多种类型的,如int,char,string等。


1.4 STL的组成
      STL有三大核心部分:容器(Container)、算法(Algorithms)、迭代器(Iterator),容器适配器(container adaptor),函数对象(functor),除此之外还有STL其他标准组件。通俗的讲:
  • 容器:装东西的东西,装水的杯子,装咸水的大海,装人的教室……STL里的容器是可容纳一些数据的模板类。
  • 算法:就是往杯子里倒水,往大海里排污,从教室里撵人……STL里的算法,就是处理容器里面数据的方法、操作。
  • 迭代器:往杯子里倒水的水壶,排污的管道,撵人的那个物业管理人员……STL里的迭代器:遍历容器中数据的对象。对存储于容器中的数据进行处理时,迭代器能从一个成员移向另一个成员。他能按预先定义的顺序在某些容器中的成员间移动。对普通的一维数组、向量、双端队列和列表来说,迭代器是一种指针。
下面让我们来看看专家是怎么说的:
  • 容器(container):容器是数据在内存中组织的方法,例如,数组、堆栈、队列、链表或二叉树(不过这些都不是STL标准容器)。STL中的容器是一种存储T(Template)类型值的有限集合的数据结构,容器的内部实现一般是类。这些值可以是对象本身,如果数据类型T代表的是Class的话。
  • 算法(algorithm):算法是应用在容器上以各种方法处理其内容的行为或功能。例如,有对容器内容排序、复制、检索和合并的算法。在STL中,算法是由模板函数表现的。这些函数不是容器类的成员函数。相反,它们是独立的函数。令人吃惊的特点之一就是其算法如此通用。不仅可以将其用于STL容器,而且可以用于普通的C++数组或任何其他应用程序指定的容器。
  • 迭代器(iterator):一旦选定一种容器类型和数据行为(算法),那么剩下唯一要他做的就是用迭代器使其相互作用。可以把达代器看作一个指向容器中元素的普通指针。可以如递增一个指针那样递增迭代器,使其依次指向容器中每一个后继的元素。迭代器是STL的一个关键部分,因为它将算法和容器连在一起。

 容器
 

2.1 向量(vector

    向量(vector容器类):#include <vector>,vector是一种动态数组,是基本数组的类模板。其内部定义了很多基本操作。既然这是一个类,那么它就会有自己的构造函数和方法。具体如何使用请参照C PLus Plus。如果对于Vector有一些不明白可以参考这里

    下面关于构造函数的演示:

#include <cstring> 
#include <vector>
#include <iostream>
using namespace std;
 
int ar[10] = {  12, 45, 234, 64, 12, 35, 63, 23, 12, 55  };
char* str = "Hello World";
 
int main()
{
    vector <int> vec1(ar, ar+10);   //first=ar,last=ar+10,不包括ar+10
    vector < char > vec2(str,str+strlen(str)); //first=str,last= str+strlen(str),
    cout<<"vec1:"<<endl;  
    //打印vec1和vec2,const_iterator是迭代器,后面会讲到
    //当然,也可以用for (int i=0; i<vec1.size(); i++)cout << vec[i];输出
    //size()是vector的一个成员函数
    for(vector<int>::const_iterator p=vec1.begin();p!=vec1.end(); ++p)
        cout<<*p;
        cout<<'\n'<<"vec2:"<<endl;
    for(vector< char >::const_iterator p1=vec2.begin();p1!=vec2.end(); ++p1)
        cout<<*p1;
    cout<<'\n';
    return 0;
}  

     为了帮助理解向量的概念,这里写了一个小例子,其中用到了vector的成员函数:begin(),end(),push_back(),assign(),front(),back(),erase(),empty(),at(),size()。

 
#include <iostream>
#include <vector>
using namespace std;
 
typedef vector<int> INTVECTOR;//自定义类型INTVECTOR
//测试vector容器的功能
 
int main()
{
    //vec1对象初始为空
    INTVECTOR vec1;  
    //vec2对象最初有10个值为6的元素 
    INTVECTOR vec2(10,6); 
    //vec3对象最初有3个值为6的元素,拷贝构造
    INTVECTOR vec3(vec2.begin(),vec2.begin()+3); 
    //声明一个名为i的双向迭代器
    INTVECTOR::iterator i;
    //从前向后显示vec1中的数据
    cout<<"vec1.begin()--vec1.end():"<<endl;
    for (i =vec1.begin(); i !=vec1.end(); ++i)
        cout << *i << " ";
    cout << endl;
    //从前向后显示vec2中的数据
    cout<<"vec2.begin()--vec2.end():"<<endl;
    for (i =vec2.begin(); i !=vec2.end(); ++i)
        cout << *i << " ";
    cout << endl;
    //从前向后显示vec3中的数据
    cout<<"vec3.begin()--vec3.end():"<<endl;
    for (i =vec3.begin(); i !=vec3.end(); ++i)
        cout << *i << " ";
    cout << endl;
    //测试添加和插入成员函数,vector不支持从前插入
    vec1.push_back(2);//从后面添加一个成员
    vec1.push_back(4);
    vec1.insert(vec1.begin()+1,5);//在vec1第一个的位置上插入成员5
    //从vec1第一的位置开始插入vec3的所有成员
    vec1.insert(vec1.begin()+1,vec3.begin(),vec3.end());
    cout<<"after push() and insert() now the vec1 is:" <<endl;
    for (i =vec1.begin(); i !=vec1.end(); ++i)
        cout << *i << " ";
    cout << endl;
    //测试赋值成员函数
    vec2.assign(8,1);   // 重新给vec2赋值,8个成员的初始值都为1
    cout<<"vec2.assign(8,1):" <<endl;
    for (i =vec2.begin(); i !=vec2.end(); ++i)
        cout << *i << " ";
    cout << endl;
    //测试引用类函数
    cout<<"vec1.front()="<<vec1.front()<<endl;//vec1第零个成员
    cout<<"vec1.back()="<<vec1.back()<<endl;//vec1的最后一个成员
    cout<<"vec1.at(4)="<<vec1.at(4)<<endl;//vec1的第五个成员
    cout<<"vec1[4]="<<vec1[4]<<endl;
    //测试移出和删除
    vec1.pop_back();//将最后一个成员移出vec1
    vec1.erase(vec1.begin()+1,vec1.end()-2);//删除成员
    cout<<"vec1.pop_back() and vec1.erase():" <<endl;
    for (i =vec1.begin(); i !=vec1.end(); ++i)
        cout << *i << " ";
    cout << endl;
    //显示序列的状态信息
    cout<<"vec1.size(): "<<vec1.size()<<endl;//打印成员个数
    cout<<"vec1.empty(): "<<vec1.empty()<<endl;//清空
}

 例1:A+B in Hogwarts

 
 
2.2 set 和multiset 容器类

     一个集合(#include<set>)是一个容器,它其中所包含的元素的值是唯一的。这在收集一个数据的具体值的时候是有用的。集合中的元素按一定的顺序排列,并被作为集合中的实例。如果你需要一个键/值对(pair)来存储数据,map(也是一个关联容器,后面将马上要讲到)是一个更好的选择。一个集合通过一个链表来组织,在插入操作和删除操作上比向量(vector)快,但查找或添加末尾的元素时会有些慢。我们来看一个简单的例子

 1 #include <iostream>
 2 #include <set>
 3 using namespace std;
 4  
 5 int main()
 6 {
 7     set<int> set1;
 8     for(int i=0; i<10; ++i)
 9         set1.insert(i);
10     for(set<int>::iterator p=set1.begin();p!=set1.end();++p)
11         cout<<*p<<"";
12     if(set1.insert(3).second)//把3插入到set1中
13 //插入成功则set1.insert(3).second返回1,否则返回0
14 //此例中,集中已经有3这个元素了,所以插入将失败
15         cout<<"set insert success";
16     else
17         cout<<"set insert failed";
18     int a[] = {4, 1, 1, 1, 1, 1, 0, 5, 1, 0};
19     multiset<int> A;
20     A.insert(set1.begin(),set1.end());
21     A.insert(a,a+10);
22     cout<<endl;
23     for(multiset<int>::iterator p=A.begin();p!=A.end();++p)
24     cout<<*p<<" ";
25     return 0;
26 }

例2:Break Standard Weight

 1 #include <iostream>
 2 #include <set>
 3 using namespace std;
 4 
 5 int GetMasses(int *n){
 6     int sum[2],  tmp;
 7     set <int> s;
 8     for(int i=0; i<2; i++)
 9         sum[i] = 0;
10     for(int i=0; i<3; i++){
11         s.insert(n[i]);
12         for(int j=0; j<3; j++){
13             if(i != j){
14                 sum[0] = n[i] + n[j];
15                 s.insert(sum[0]);
16                 if(n[i]>n[j]){
17                     sum[1] = n[i]-n[j];
18                     s.insert(sum[1]);
19                 }
20                 else{
21                     sum[1] = n[j]-n[i];
22                     if(sum[1] > 0) 
23                         s.insert(sum[1]);
24                 }    
25                 for(int k=0; k<3; k++){
26                     if(k != i && k != j){
27                         for(int m=0; m<2; m++){
28                             s.insert(sum[m]+n[k]);
29                             tmp =sum[m] - n[k];
30                             if (tmp >0)
31                                 s.insert(tmp);
32                         }
33                     }    
34                 }
35             }
36         }
37     }
38     return s.size();
39 }
40 
41 int main()
42 {
43     int T, sum, n[3];
44     cin >> T;
45     while(T--){
46         int x, y, max, ans;
47         cin >> x >> y;
48         sum = x+y;
49         
50         ans = 0;
51         for(int i=1; i<=x/2; i++){
52             n[0] = i;
53             n[1] = x-i;
54             n[2] = y;
55             max = GetMasses(n);
56             if(max > ans)
57                 ans = max;
58         }
59         
60         for(int i=1; i<= y/2; i++){
61             n[0] = i;
62             n[1] = y-i;
63             n[2] = x;
64             max = GetMasses(n);
65             if(max > ans)
66                 ans = max;            
67         }
68         cout << ans << endl;
69     }
70     return 0;
71 }
View Code

 


 

  2.3  映射和多重映射(map 和multimap)

     映射和多重映射(#include<map>)基于某一类型Key的键集的存在,提供对T类型的数据进行快速和高效的检索。对map而言,键只是指存储在容器中的某一成员。Map不支持副本键,multimap支持副本键。Map和multimap对象包涵了键和各个键有关的值,键和值的数据类型是不相同的,这与set不同。set中的key和value是Key类型的,而map中的key和value是一个pair结构中的两个分量。Map支持下表运算符operator[],用访问普通数组的方式访问map,不过下标为map的键。在multimap中一个键可以对应多个不同的值。

#include <iostream>
#include <map>
using namespace std;
 
int main()
{
    map<char,int,less<char> > map1;
    map<char,int,less<char> >::iterator mapIter;
    //char 是键的类型,int是值的类型
    //下面是初始化,与数组类似
    //也可以用map1.insert(map<char,int,less<char> >::value_type(''c'',3));
    map1['c']=3;
    map1['d']=4;
    map1['a']=1;
    map1['b']=2;
    for(mapIter=map1.begin();mapIter!=map1.end();++mapIter)
        cout<<" "<<(*mapIter).first<<": "<<(*mapIter).second;
    //first对应定义中的char键,second对应定义中的int值 
    //检索对应于d键的值是这样做的:
    map<char,int,less<char> >::const_iterator ptr;
    ptr=map1.find('d');
    cout<<'\n'<<" "<<(*ptr).first<<" 键对应于值:"<<(*ptr).second;
    return 0;
}

 


 

算法 

#inlcude <algorithm>

STL中算法的大部分都不作为某些特定容器类的成员函数,他们是泛型的,每个算法都有处理大量不同容器类中数据的使用。值得注意的是,STL中的算法大多有多种版本,用户可以依照具体的情况选择合适版本。中在STL的泛型算法中有4类基本的算法:

变序型队列算法:可以改变容器内的数据;

非变序型队列算法:处理容器内的数据而不改变他们;

排序值算法:包涵对容器中的值进行排序和合并的算法,还有二叉搜索算法、通用数值算法。(注:STL的算法并不只是针对STL容器,对一般容器也是适用的。)

变序型队列算法:又叫可修改的序列算法。这类算法有复制(copy)算法、交换(swap)算法、替代(replace)算法、删除(clear)算法,移动(remove)算法、翻转(reverse)算法等等。这些算法可以改变容器中的数据(数据值和值在容器中的位置)。

  3.1 翻转和复制(reverse()和copy()
#include <iostream>
#include <algorithm>
#include <iterator>
//下面用到了输出迭代器ostream_iterator
using namespace std;
 
int main()
{
    int arr[6]={1,12,3,2,1215,90};
    int arr1[7];
    int arr2[6]={2,5,6,9,0,-56};
    copy(arr,(arr+6),arr1);//将数组aar复制到arr1
    cout<<"arr[6] copy to arr1[7],now arr1: "<<endl;
    for(int i=0;i<7;i++)
        cout<<" "<<arr1[i];
    reverse(arr,arr+6);//将排好序的arr翻转
    cout<<'\n'<<"arr reversed ,now arr:"<<endl;
    copy(arr,arr+6,ostream_iterator<int>(cout, " "));//复制到输出迭代器
    swap_ranges(arr,arr+6,arr2);//交换arr和arr2序列
    cout<<'\n'<<"arr swaped to arr2,now arr:"<<endl;
    copy(arr,arr+6,ostream_iterator<int>(cout, " "));
    cout<<'\n'<<"arr2:"<<endl;
    copy(arr2,arr2+6,ostream_iterator<int>(cout, " "));
    return 0;
}

3.2 查找(find()/Search()

Find() 其功能是在序列[first,last-1]中查找value值,如果找到,就返回一个指向value在序列中第一次出现的迭代,如果没有找到,就返回一个指向last的迭代(last并不属于序列)。

Search() 其功能是在源序列[first1,last1-1]查找目标序列[first2,last2-1]如果查找成功,就返回一个指向源序列中目标序列出现的首位置的迭代。查找失败则返回一个指向last的迭代。

3.3 排序

排序算法(sort algorithm):这一类算法很多,功能强大同时也相对复杂一些。这些算法依赖的是关系运算。在这里我只介绍其中比较简单的几种排序算法:sort(),merge(),includes()

#include <iostream>
#include <algorithm>
using namespace std;
 
int main()
{
    int a[10]={12,0,5,3,6,8,9,34,32,18};
    int b[5]={5,3,6,8,9};
    int d[15];
    sort(a,a+10);
    for(int i=0;i<10;i++)
      cout<<" "<<a[i];
    sort(b,b+5);
    if(includes(a,a+10,b,b+5))
       cout<<'\n'<<"sorted b members are included in a."<<endl;
    else
       cout<<"sorted a dosn`t contain sorted b!";
    merge(a,a+10,b,b+5,d);
    for(int j=0;j<15;j++)
       cout<<" "<<d[j];
    return 0;

例3:Applications

#include <iostream>
#include <cstring>
#include <iomanip>
#include <algorithm>
using namespace std;

struct TEAM{
    string name;
    int rank;
} team[505];

struct MAN{
    string name, team;
    char sex;
    double score;
    int nP, nC;
} man[505]; 

int mao[505], sur[505], r, s; 

bool IsPrime(int num){
    for(int i=2; i*i<=num; i++){
        if(num%i==0)
            return 0;
    }
    return 1;
}

double Max(double a,double b){
    return (a>b)?a:b;    
}

double jamcal(int r){
    return Max(0,((r-1200)/100.0)*1.5);
}

double GetScoreProblem(int num){
    for(int i=0; i<r; i++)
        if(num == mao[i])
            return 2.5;
    for(int i=0; i<s; i++)
        if(num == sur[i])
            return 1.5;
    if(IsPrime(num)) return 1;
    return 0.3;
}

bool cmpScore(MAN x, MAN y){
    return x.score > y.score;    
}

bool cmpRate(int x, int y){
    return x > y;
} 

int main()
{
    int T, n, m, q, tmp, c[1005];
    cin >> T;
    while(T--){
        cin >> n >> m;

        cin >> r; 
        for(int i=0; i<r; i++)
            cin >> mao[i];
        cin >> s;
        for(int i=0; i<s; i++)
            cin >> sur[i];
        cin >> q;
        for(int i=0; i<q; i++)
            cin >> team[i].name >> team[i].rank;
        for(int i=0; i<n; i++){
            man[i].score = 0;
            cin>>man[i].name>>man[i].team>>man[i].sex>>man[i].nP>>man[i].nC;
            for(int j=0; j<man[i].nP; j++){
                cin >> tmp;
                man[i].score += GetScoreProblem(tmp);
            }
            
            //Get some pts from the competition
            for(int j=0; j<q; j++){
                if(man[i].team == team[j].name){
                    if(team[j].rank == 1)
                        man[i].score += 36;
                    else if(team[j].rank == 2)
                        man[i].score += 27;
                    else if(team[j].rank == 3)
                        man[i].score += 18; 
                }
                
            }
            
            //Get some pts form JapanJam
            memset(c, 0, sizeof(c));
            for(int j=0; j<man[i].nC; j++){
                cin >> c[j];
            }
            sort(c, c+man[i].nC, cmpRate);
            man[i].score += jamcal(c[2]);
            //man[i].score += std::max(0, (c[2]-1200)/100)*1.5;
            
            //for girl
            if(man[i].sex == 'F')
                man[i].score += 33;
        }
        sort(man,man+n, cmpScore);
        //output
        for(int i=0; i<m; i++){
            cout<<man[i].name<<" "<<setiosflags(ios::fixed)<<setprecision(3)<<man[i].score<<endl;
        } 
            
        
    } 
    return 0;
}

 


参考文献
[1] http://www.cnblogs.com/ACMan/archive/2012/05/30/2526927.html
[2] http://www.cplusplus.com/reference/stl/
[3] http://www.codeproject.com/Articles/181/Using-STL
[4] http://net.pku.edu.cn/~yhf/UsingSTL.htm

 

2.1 基本容器——向量(vector

转载于:https://www.cnblogs.com/linspirit/articles/3792099.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值