暑期培训-STL基础

STL中的几个基本概念

  • 容器:可容纳各种数据类型的数据结构。(如 vector )
  • 迭代器:可依次存取容器中元素的东西
  • 算法:用来操作容器中的元素的函数模板。例如,STL用sort()来对一个vector中的数据进行排序,用find()来搜索一个list中的对象

比如,数组int array[100]就是一个容器,而int *类型的指针变量就可以作为迭代器,可以为这个容器编写一个排序的算法

  1. 顺序容器

    vector: 后部插入/删除,直接访问

    deque: 前/后插入/删除,直接访问

    list: 双向链表,任意位置插入/删除

  2. 关联容器

    set: 快速查找,无重复元素
    multiset: 快速查找,可有重复元素

    map: 一对一映射,无重复元素,基于关键字查找

    multimap: 一对一映射,可有重复元素,基于关键字查找

    前两者合称为第一类容器

  3. 容器适配器

    stack: LIFO

    queue: FIFO

    priority_queue: 优先级高的元素先出

顺序容器简介
  1. vector 头文件 <vector>

    实际上就是个动态数组。随机存取任何元素都能在常数时间完成。在尾端增删元素具有较佳的性能

  2. deque 头文件 <deque>

    也是个动态数组,随机存取任何元素都能在常数时间内完成(但性能次于vector)。在两端增删元素具有较佳的性能。

  3. list 头文件 <list>

    双向链表,在任何位置增删元素都能在常数时间完成。不支持随机存取

    上述三种容器称为顺序容器,是因为元素的插入位置同元素的值无关

关联容器简介

关联容器内的元素是排序的,插入任何元素,都按相应的排序准则来确定其位置。关联式容器的特点是在查找时具有非常好的性能。

  1. set/multiset 头文件 <set>

    set即集合。set中不允许相同的元素,multiset中允许存在相同的元素

  2. map/multimap 头文件 <map>

    mapset的不同在于map中存放的是成对的key/value

    并根据key对元素进行排序,可快速地根据key来检索元素mapmultimap的不同在于是否允许多个元素有相同的key

    上述4种容器通常以平衡二叉树方式实现,插入和检索的时间都是O(logN)

容器的共有成员函数
  1. 所有标准容器共有的成员函数

    相当于按词典顺序比较两个容器大小的运算符:

    =,<,<=,>,>=,==,!=

    empty: 判断容器中是否有元素
    max_size: 容器中最多能装多少个元素

    size: 容器中元素的个数

    swap: 交换两个容器的内容

  2. 只在第一类容器中的函数

    begin: 返回指向容器中第一个元素的迭代器

    end: 返回指向容器中最后一个元素后面的位置的迭代器

    rbegin: 返回指向容器中最后一个元素的迭代器

    rend: 返回指向容器中第一个元素前面的位置的迭代器

    erase: 从容器中删除一个或几个元素

迭代器

定义:提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节

用于指向第一类容器中的元素。有const和非const两种。通过迭代器可以读取它指向的元素,通过非const迭代器还能修改其指向的元素。迭代器用法和指针类似

定义一个容器类的迭代器的方法可以是:

容器类名::iterator 变量名容器类名::const_iterator 变量名

访问一个迭代器指向的元素:

*迭代器变量名

迭代器上可以执行++操作,以指向容器中下一个元素。如果迭代器到达了容器中的最后一个元素的后面,则迭代器变成past-the-end

使用一个past-the-end值的迭代器来访问对象是非法的,就好像使用NULL或未初始化的指针一样。


不同容器上支持的迭代器功能强弱有所不同

容器的迭代器的功能强弱,决定了该容器是否支持STL中的某种算法

  • 只有第一类容器能用迭代器遍历
  • 排序算法需要通过随机迭代器来访问容器中的元素,那么有的容器就不支持排序算法。
STL中的迭代器

STL中的迭代器按功能有弱到强分为5种

  1. 输入: Input iterators提供对数据的只读访问
  2. 输出: Output iterators提供对数据的只写访问
  3. 正向: Forward iterators提供读写操作,并能一次一个地向前推进迭代器
  4. 双向: Bidirectional iterators提供读写操作,并能一次一个地向前和向后移动。
  5. 随机访问: Random access iterators提供读写操作,并能在数据中随机移动

编号大的迭代器拥有编号小的迭代器的所有功能,能当做编号小的迭代器使用

不同迭代器所能进行的操作(功能)
  • 所有迭代器:++p,p++

  • 输入迭代器:*p,p = p1,p == p1,p != p1

  • 输出迭代器:*p,p = p1

  • 正向迭代器:上面全面

  • 双向迭代器:上面全部,--p,p--

  • 随机访问迭代器:上面全部,以及

    • p+=i,p-=i

    • p+i: 返回指向p后面的第i个元素的迭代器

    • p-i: 返回指向p下面的第i个元素的迭代器

    • p[i]: p后面的第i个元素的引用

    • p<p1,p<=p1,p>p1,p>=p1

容器所支持的迭代器类别
容器迭代器类别
vector随机
deque随机
list双向
set/multiset双向
map/multimap双向
stack不支持迭代器
queue不支持迭代器
priority_queue不支持迭代器

算法简介

STL中提供能在各种容器中通用的算法,比如插入,删除,查找,排序等。大约有70种标准算法

算法举例
template<class InIt,class T>
InIt find<InIt first,InIt last,const T& val>;

first和last这两个参数都是容器的迭代器,它们给出了容器中的查找区间起点和终点,这个区间是左闭右开的区间。函数的返回值是一个迭代器,如果找到,该迭代器指向被找到的元素,如果没有找到,该迭代器指向查找区间的终点。

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

int main()
{
    int array[10] = {10,20,30,40};
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    vector<int>::iterator p;
    p = find(v.begin(),v.end(),3);
    if(p != v.end())
        cout<<*p<<endl;
    p = find(v.begin(),v.end(),9);
    if(p == v.end())
        cout<<"not found"<<endl;
    p = find(v.begin()+1,v.end()-2,1);
    if(p != v.end())
        cout<<*p<<endl;
    int *pp = find(array,array+4,20);
    cout<<*pp<<endl;

    return 0;
}

顺序容器

除了上述共同操作外,顺序容器还有以下共同操作

front(): 返回容器中第一个元素的引用

back(): 返回容器中最后一个元素的引用

push_back(): 在容器末尾增加新元素

pop_back(): 删除容器末尾的元素

对于list<double>

list<double>::reference 实际上就是double &

list<double>::const_reference 实际上就是const double &

#include<iostream>
#include<vector>

using namespace std;

int main()
{
    int i;
    int a[5] = {1,2,3,4,5};
    vector<int> v(5);
    cout<<v.end()-v.begin()<<endl;
    for(i = 0 ; i < v.size() ; i++)
        v[i] = i;
    v.at(4) = 100;
    for(i = 0 ; i < v.size() ; i++)
        cout<<v[i]<<",";
    cout<<endl;

    vector<int> v2(a,a+5);  // 构造函数
    v2.insert(v2.begin()+2,13); // 在begin()+2位置插入法13
    for(i = 0 ; i < v2.size() ; i++)
        cout<<v2[i]<<",";
    cout<<endl;
    return 0;
}
#include<iostream>
#include<vector>

using namespace std;

int main()
{
    const int SIZE = 5;
    int a[SIZE] = {1,2,3,4,5};
    vector<int> v(a,a+5);   // 构造函数
    try{
        v.at(100) = 7;
    }
    catch(out_of_range e){
        cout<<e.what()<<endl;
    }
    cout<<v.front()<<","<<v.back()<<endl;
    v.erase(v.begin());
    ostream_iterator<int> output(cout,"*");
    copy(v.begin(),v.end(),output);
    v.erase(v.begin(),v.end()); // 等效于v.clear()
    if(v.empty())
        cout<<"empty"<<endl;
    v.insert(v.begin(),a,a+SIZE);
    copy(v.begin(),v.end(),output);
    return 0;
}

list容器

除了具有所有顺序容器都有的成员函数以外,还支持8个成员函数

  • push_front: 在前面插入
  • pop_front: 删除前面的元素
  • sort: 排序(list不支持STL的算法sort)
  • remove: 删除和指定值相等的所有元素
  • unique: 删除所有和前一个元素相同的元素
  • merge: 合并两个链表,并清空被合并的那个
  • reverse: 颠倒链表
  • splice: 在指定位置前面插入另一链表中的一个或多个元素,并在另一个链表中删除被插入的元素

deque容器

所有适用于vector的操作都适用于deque

deque还有push_front(将元素插入到前面)和pop_front(删除最前面的元素)操作

关联容器

除了各容器都有的函数外,还支持一下成员函数:设m表示容器,k表示键值

  • m.find(k): 如果容器中存在建为k的元素,则返回指向该元素的迭代器。如果不存在,则返回end()值。
  • m.lower_bound(k): 返回一个迭代器,指向键不小于k的第一个元素
  • m.upper_bound(k): 返回一个迭代器,指向键大于k的第一个元素
  • m.count(k): 返回m中k的出现次数
  • 插入元素用insert
pair模板

pair模板类用来绑定两个对象为一个新的对象,该类型在头文件中定义

  • pair<T1,T2> p1: 创建一个空的pair对象,它的两个元素分别是T1和T2类型,采用值初始化
  • pair<T1,T2> p1(v1,v2)
  • make_pair(v1,v2): 以v1v2值创建一个新的pair对象,其元素类型分别是v1v2类型
  • p.first: 返回p中名为first的(公有)数据成员
  • p.second: 返回p中名为second的(公有)数据成员
#include<iostream>
#include<set>
using namespace std;

int main(void)
{
    typedef set<double,less<double> >double_set;
    const int SIZE = 5;
    double a[SIZE] = {2.1,4.2,9.5,2.1,3.7};
    double_set doubleSet(a,a+SIZE);
    pair<double_set::const_iterator,bool> p;
    p = doubleSet.insert(9.5);
    if(p.second)
        cout<<"1)"<<*(p.first)<<" inserted"<<endl;
    else
        cout<<"2)"<<*(p.first)<<" not inserted"<<endl;

    return 0;
}

输出:

2) 9.5 not inserted

缺省情况下用less定义关键字的“小于”关系

map
#include<iostream>
#include<map>
using namespace std;

ostream &operator <<(ostream &o,const pair<int,double>& p)
{
    o<<"("<<p.first<<","<<p.second<<")";
    return o;
}

int main()
{
    typedef map<int,double,less<int> > mmid;
    mmid pairs;
    cout<<"1)"<<pairs.count(15)<<endl;
    //pairs.insert(mmid::value_type(15,2.7));
    pairs.insert(make_pair(15,99.3));   // make_pair生成pair对象
    cout<<"2)"<<pairs.count(15)<<endl;
    pairs.insert(mmid::value_type(20,9.3));
    mmid::iterator i;
    cout<<"3)";
    for(i = pairs.begin() ; i != pairs.end() ; i++)
        cout<<*i<<",";
    cout<<endl;
    cout<<"4)";
    int n = pairs[40];  // 如果没有关键字为40的元素,则插入一个
    for(i = pairs.begin() ; i != pairs.end() ; i++)
        cout<<*i<<",";
    cout<<endl;
    cout<<"5)";
    pairs[15] = 6.28;   // 把关键字为15的元素值改成6.28
    for(i = pairs.begin() ; i != pairs.end() ; i++)
        cout<<*i<<",";

    return 0;
}
运行结果

容器适配器: stack

stack是后进先出的数据结构,只能插入,删除,访问栈顶的元素

stack上可以进行以下操作
  • push: 插入元素
  • pop:弹出元素
  • top:返回栈顶元素的引用

容器适配器: queue

同样也有pushpoptop函数

但是push发生在队尾,pop,top发生在对头,先进先出

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

int main()
{
    const int SIZE = 10;
    int a1[] = {2,8,1,50,3,100,8,9,10,2};
    vector<int> v(a1,a1+SIZE);
    ostream_iterator<int> output(cout," ");
    vector<int>::iterator location;
    location = find(v.begin(),v.end(),10);
    if(location != v.end()){
        cout<<endl<<"1)"<<location-v.begin();
    }
    sort(v.begin(),v.end());
    if(binary_search(v.begin(),v.end(),9))
        cout<<endl<<"3)"<<"9 found";
    else
        cout<<endl<<"3)"<<"9 not found";
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值