C++ STL(一)

一、STL基本概念

容器:可容纳各种数据类型的通用数据结构

迭代器:用于依次存取容器中元素。

算法:操作容器中元素的函数模板。

二、容器

1.容器概述

顺序容器:vector,deque,list

关联容器:set,multiset,map,multimap

容器适配器:stack,queue,priority_queue

2.顺序容器

特点:容器并非排序,元素的插入位置与元素的值无关。

  • vector:一种随机访问的数组类型,提供了对数组元素进行快速随机访问以及在序列尾部进行快速的插入和删除操作的功能。可以再需要的时候修改其自身的大小,可以认为是动态数组。支持迭代器类别:随机访问
  • deque:一种随机访问的数组类型,提供了序列两端快速进行插入和删除操作的功能。可以再需要的时候修改其自身的大小,可以认为是双向队列。支持迭代器类别:随机访问
  • list:一种不支持随机访问的数组类型,插入和删除所花费的时间是固定的,与位置无关。可认为是双向链表。支持迭代器类别:双向

顺序容器常用的成员函数:

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

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

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

pop_back:删除容器末尾的元素

erase:删除迭代器指向的元素,或删除一个区间,返回被删除元素后面的那个元素的迭代器。

 

3.关联容器

特点:元素始终是排序的,通常都是以平衡二叉树实现,在查找时具有较好的性能。

  • set:一种随机存取的容器,其关键字和数据元素是同一个值。所有元素都必须具有惟一值。支持迭代器类别:双向
  • multiset:一种随机存取的容器,其关键字和数据元素是同一个值。可以包含重复的元素。支持迭代器类别:双向
  • map:一种包含成对数值的容器,一个值是实际数据值,另一个是用来寻找数据的关键字。一个特定的关键字只能与一个元素关联。支持迭代器类别:双向
  • multimap:一种包含成对数值的容器,一个值是实际数据值,另一个是用来寻找数据的关键字。一个关键字可以与多个数据元素关联。支持迭代器类别:双向

关联容器常用成员函数(顺序容器也有)

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

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

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

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

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

clear:从容器中删除所有元素

4.容器适配器(不支持迭代器)

  • stack:适配器容器类型,用vector,deque或list对象创建了一个先进后出容器,可认为是栈
  • queue:适配器容器类型,用deque或list对象创建了一个先进先出容器,可认为是队列
  • priority_queue:适配器容器类型,用vector或deque对象创建了一个排序队列,可认为是优先级队列

三、迭代器

1.概述

  • 用于指向顺序容器和关联容器中的元素
  • 可以通过迭代器读取指向的元素
  • 迭代器有const和非const,对于非const迭代器能修改其指向的元素

2.迭代器类别

迭代器类别

说明

输入

从容器中读取元素。输入迭代器只能一次读入一个元素向前移动,

输入迭代器只支持一遍算法,同一个输入迭代器不能两遍遍历一个序列

输出

向容器中写入元素。输出迭代器只能一次一个元素向前移动。

输出迭代器只支持一遍算法,统一输出迭代器不能两次遍历一个序列

正向

组合输入迭代器和输出迭代器的功能,并保留在容器中的位置

双向

组合正向迭代器和逆向迭代器的功能,支持多遍算法

随机访问

组合双向迭代器的功能与直接访问容器中任何元素的功能,即可向前向后跳过任意个元素

3.迭代器操作

每种迭代器均可进行包括表中前一种迭代器可进行的操作。

迭代器操作

说明

所有迭代器

p++

后置自增迭代器

++p

前置自增迭代器

输入迭代器

*p

复引用迭代器,作为右值

p=p1

将一个迭代器赋给另一个迭代器

p==p1

比较迭代器的相等性

p!=p1

比较迭代器的不等性

输出迭代器

*p

复引用迭代器,作为左值

p=p1

将一个迭代器赋给另一个迭代器

正向迭代器

提供输入输出迭代器的所有功能

双向迭代器

--p

前置自减迭代器

p--

后置自减迭代器

随机迭代器

p+=i

将迭代器递增i位

p-=i

将迭代器递减i位

p+i

在p位加i位后的迭代器

p-i

在p位减i位后的迭代器

p

返回p位元素偏离i位的元素引用

p<p1

如果迭代器p的位置在p1前,返回true,否则返回false

p<=p1

p的位置在p1的前面或同一位置时返回true,否则返回false

p>p1

如果迭代器p的位置在p1后,返回true,否则返回false

p>=p1

p的位置在p1的后面或同一位置时返回true,否则返回false

4.示例

使用迭代器

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

int main()
{
    // 定义了一个存放int类型元素的数组
    vector<int> v;

    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);

    // 定义const迭代器
    vector<int>::const_iterator i;
    for(i = v.begin(); i != v.end(); ++i)
        cout << *i << " ";
    cout << endl;

    // 定义反向迭代器
    vector<int>::reverse_iterator r;
    for(r = v.rbegin(); r != v.rend(); ++r)
        cout << *r << " ";
    cout << endl;

    // 定义非const类型迭代器
    vector<int>::iterator j;
    for(j = v.begin(); j != v.end(); ++j)
        *j = 100;
    for(i = v.begin(); i != v.end(); ++i)
        cout << *i << " ";

    /*
    输出:
    1 2 3 4
    4 3 2 1
    100 100 100 100
    */
}

遍历vector的方法有多种,deque也是这样:

#include <vector>
#include <iostream>

using namespace std;

int main()
{
    vector<int> v(100);

    // 1
    for(unsigned int i = 0; i < v.size(); ++i)
        cout << v[i] << " ";
    // 2
    vector<int>::const_iterator ii;
    for(ii = v.begin(); ii != v.end(); ++ii)
        cout << *ii << " ";
    // 3
    for(ii = v.begin(); ii < v.end();)
    {
        cout << *ii << " ";
        ii = ii + 2;
    }
}

但在遍历list需要注意不能使用随机访问的方法

#include <list>
#include <iostream>

using namespace std;

int main()
{
    list<int> v(10);
    list<int>::const_iterator ii;
    for(ii = v.begin(); ii != v.end(); ++ii)
        cout << *ii << " ";
}

注意之前上个示例所示的另外两种方法在此都不能使用。

四、算法

1.概述

  • 算法即函数模板
  • 算法通过迭代器操纵容器中的元素
  • 算法可以处理容器,也可以处理普通数组

2.算法示例

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

using namespace std;

int main()
{
    int a[10] = {1,2,3,4};
    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(), 89);
    if(p != v.end())
        cout << *p << endl;
    else
        cout << "not found" << endl;

    // 整个容器:[1,2,3,4], 查找区间: [2,3)
    p = find(v.begin() + 1, v.end() - 2, 1);

    // 数组名是迭代器
    int * pp = find(a, a + 4, 4);
    cout << *pp << endl;
}

 

五、函数对象

#include <iostream>

using namespace std;

class CmyAverage{
public:
    double operator() (int a1, int a2, int a3)
    {
        return (a1 + a2 + a3) / 3.0;
    }
};
int main()
{
    CmyAverage average;
    cout << average(1,3,3);
    return 0;
}

1.Accumulate函数对象

例如accumulate的函数头

template<class InIt, class T, class Pred>
T accumulate(InIt first, InIt last, T val, Pred pr)

这里的pr就是函数对象,通过的[first,last)中的每个迭代器执行val = pr(val, *I),返回最终结果。

以Accumulate的源代码为例,accumulate有两个不一样的版本,一个是不带下面所示的_BinaryOperation参数,这相当于使用默认形式下的accumulate,本文所给的是通过自定义函数进行accumulate。

template<typename _InputIterator, typename _Tp,
            typename _BinaryOperation>
    _Tp accumulate(_InputIterator _first, _InputIterator _last,
                   _Tp _init,   _BinaryOperation _binary_op)
    {
        for(; _first != _last; ++_first)
            _init = _binary_op(_init, *_first);
        return _init;
    }

结合上面Accumulate的源代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <functional>

using namespace std;

int SumSquares(int total, int value)
{ return total + value * value; }

template <class T>
void PrintInterval(T first, T last)
{
    for(; first != last; ++first)
        cout << *first << " ";
    cout << endl;
}

template <class T>
class SumPowers{
private:
    int power;
public:
    SumPowers(int p):power(p){ }
    const T operator() (const T & total, const T & value)
    {
        T v = value;
        for(int i = 0; i < power - 1; ++i)
            v = v * value;
        return total + v;
    }
};

int main()
{
    const int SIZE = 10;
    int a1[] = { 1,2,3,4,5,6,7,8,9,10 };
    vector<int> v(a1,a1+SIZE);
    cout << "1) ";
    PrintInterval(v.begin(),v.end());
    int result = accumulate(v.begin(),v.end(),0,SumSquares);
    cout << "2) 平方和:" << result << endl;
    result = accumulate(v.begin(),v.end(),0,SumPowers<int>(3));
    cout << "3) 立方和:" << result << endl;
    result = accumulate(v.begin(),v.end(),0,SumPowers<int>(4));
    cout << "4) 4次方和:" << result;
    return 0;
}

2.greater函数对象

template<class T>
struct greater : public binary_function<T, T, bool>
{
    bool operator() (const T & x, const T & y) const
    {
        return x > y;
    }
};

template<class Arg1, class Arg2, class Result>
struct binary_function{
    typedef Arg1 first_argument_type;
    typedef Arg2 second_argument_type;
    typedef Result result_type;
};

greater函数模板生成函数对象。这里自定义函数对象MyLess

#include <iostream>
#include <list>
#include <iterator>

using namespace std;

class MyLess{
public:
    bool operator() (const int & c1, const int & c2)
    {
        return (c1 % 10) < (c2 % 10);
    }
};

int main()
{
    const int size = 5;
    int a[size] = {5, 21, 14, 2, 3};
    list<int> lst(a, a + size);
    lst.sort(MyLess());
    ostream_iterator<int> output(cout, ",");
    copy(lst.begin(), lst.end(), output);
    cout << endl;
    // 进行降序排序
    lst.sort(greater<int>());

    copy(lst.begin(), lst.end(), output);
    cout << endl;
}

一个练习就是写出下面的MyMax函数

#include <iostream>
#include <list>
#include <iterator>

using namespace std;

class MyLess{
public:
    bool operator() (int a1, int a2)
    {
        if((a1 % 10) < (a2 % 10))
            return true;
        else
            return false;
    }
};

bool MyCompare(int a1, int a2)
{
    if((a1 % 10) < (a2 % 10))
        return false;
    else
        return true;
}

template <class T, class Pred>
T MyMax(T * a, int len , Pred fun)
{
    T temp = a[0];
    for(int i = 1; i < len; ++i)
    {
        if(fun(temp, a[i]))
            temp = a[i];
    }
    return temp;
}

int main()
{
    int a[] = {35, 7, 13, 19, 12};
    cout << MyMax(a, 5, MyLess()) << endl;
    cout << MyMax(a, 5, MyCompare) << endl;
    return 0;
}

参考:

《C++ Primer》第五版

郭炜老师的《C++面向对象程序设计》

猜你喜欢

转载自blog.csdn.net/adorkable_thief/article/details/85320640