【C++】:STL容器总结以及算法(algorithm)介绍

容器的共通能力

  • 所有容器提供的都是值(value)语意,而非引用(reference)语意。容器执行插入元素的操作时,内部实施拷贝动作。所以STL容器内存储的元素必须能够被拷贝(必须提供拷贝构造函数)。
  • 除了queue与stack外,每个容器都提供可返回迭代器的函数,运用返回的迭代器就可以访问元素。
  • 通常STL不会丢出异常。要求使用者确保传入正确的参数。
  • 每个容器都提供了一个默认构造函数跟一个默认拷贝构造函数

如已有容器vecIntA。
vector< int > vecIntB(vecIntA); //调用拷贝构造函数,复制vecIntA到vecIntB中。

  • 与大小相关的操作方法(c代表容器):
c.size();   //返回容器中元素的个数
c.empty();   //判断容器是否为空
  • 比较操作(c1,c2代表容器):
c1 == c2     判断c1是否等于c2
c1 != c2      判断c1是否不等于c2
c1 = c2        把c2的所有元素指派给c1

容器的选择时机

这里写图片描述

  • Vector的使用场景:比如软件历史操作记录的存储,我们经常要查看历史记录,比如上一次的记录,上上次的记录,但却不会去删除记录,因为记录是事实的描述。
  • deque的使用场景:比如排队购票系统,对排队者的存储可以采用deque,支持头端的快速移除,尾端的快速添加。如果采用vector,则头端移除时,会移动大量的数据,速度慢。

vector与deque的比较:
一:vector.at()比deque.at()效率高,比如vector.at(0)是固定的,deque的开始位置却是不固定的。
二:如果有大量释放操作的话,vector花的时间更少,这跟二者的内部实现有关。
三:deque支持头部的快速插入与快速移除,这是deque的优点。

  • list的使用场景:比如公交车乘客的存储,随时可能有乘客下车,支持频繁的不确实位置元素的移除插入。
  • set的使用场景:比如对手机游戏的个人得分记录的存储,存储要求从高分到低分的顺序排列。
  • map的使用场景:比如按ID号存储十万个用户,想要快速要通过ID查找对应的用户。二叉树的查找效率,这时就体现出来了。如果是vector容器,最坏的情况下可能要遍历完整个容器才能找到该用户。

算法(Algorithm)

1.简介

算法部分主要由头文件< algorithm >,< numeric >和< functional >组成。

  • < algorithm >是所有STL头文件中最大的一个,其中常用到的功能范围涉及到比较、交换、查找、遍历操作、复制、修改、反转、排序、合并等等。
  • < numeric >体积很小,只包括几个在序列上面进行简单数学运算的模板函数,包括加法和乘法在序列上的一些操作。
  • < functional >中则定义了一些模板类,用以声明函数对象。

STL提供了大量实现算法的模版函数,只要我们熟悉了STL之后,许多代码可以被大大的化简,只需要通过调用一两个算法模板,就可以完成所需要的功能,从而大大地提升效率。

2.使用之前的准备

#include <algorithm>
#include <numeric>
#include <functional>
using namespace std;

3.常用的查找算法

  • adjacent_find(): 在iterator对标识元素范围内,查找一对相邻重复元素,找到则返回指向这对元素的第一个元素的迭代器。否则返回past-the-end。

例如:vecInt是用vector< int >声明的容器,现已包含1,2,2,4,5元素。
vector< int >::iterator it=adjacent_find(vecInt.begin(),vecInt.end());
此时 *it == 2

  • binary_search: 在有序序列中查找value,找到则返回true。注意:在无序序列中,不可使用。

例如: setInt是用set< int >声明的容器,现已包含1,3,5,7,9元素。
bool bFind = binary_search(setInt.begin(),setInt.end(),5);
此时 bFind == true

  • count: 利用等于操作符,把标志范围内的元素与输入值比较,返回相等的个数。
    count_if: 利用输入的函数,对标志范围内的元素进行比较操作,返回结果为true的个数。

例如:vecInt是用vector< int >声明的容器,已包含1,3,5,7,9元素,现要求求出大于等于3的元素个数

//先定义比较函数
//这就类似于之前讲到过的functor 
bool GreaterThree(int iNum)
{
        if(iNum>=3)
        {
            return true;
        }
        else
        {
            return false;
        }
}
int iCount = count_if(vecIntA.begin(), vecIntA.end(), GreaterThree);

functor讲解

  • equal_range: 返回一对iterator,第一个表示lower_bound,第二个表示upper_bound。
  • find: 利用底层元素的等于操作符,对指定范围内的元素与输入值进行比较。当匹配时,结束搜索,返回该元素的迭代器。
  • find_if: 使用输入的函数代替等于操作符执行find。返回被找到的元素的迭代器。

例如: vecInt是用vector< int >声明的容器,已包含1,3,5,7,9
vector< int >::iterator it = find(vecInt.begin(),vecInt.end(),5);
此时 *it == 5
例如:vecInt是用vector< int >声明的容器,已包含1,3,5,3,9元素。现要找出第一个大于等于3的元素的迭代器。
vector< int >::iterator it = find_if(vecInt.begin(),vecInt.end(),GreaterThree);
此时 it==3, (it+1)==5, (it+2)==3, (it+3)==9

4.常用的排序算法

  • random_shuffle: 对指定范围内的元素随机调整次序。
    reverse: 对指定范围内元素重新反序排序。

  • merge: 合并两个有序序列,存放到另一个序列。

例如:vecIntA,vecIntB,vecIntC是用vector< int >声明的容器,vecIntA已包含1,3,5,7,9元素,vecIntB已包含2,4,6,8元素
vecIntC.resize(9); //扩大容量
merge(vecIntA.begin(),vecIntA.end(),vecIntB.begin(),vecIntB.end(),vecIntC.begin());
此时vecIntC就存放了按顺序的1,2,3,4,5,6,7,8,9九个元素

  • sort: 以默认升序的方式重新排列指定范围内的元素。若要改排序规则,可以输入比较函数。

例如: vecInt是用vector< int >声明的容器,已包含2,1,4,3,6,5元素
sort(vecInt.begin(),vecInt.end());
此时,vecInt包含了1,2,3,4,5,6元素。
如果vector< T >,T是自定义类型,则要提供T类型的比较函数。

//这里的compare也是有functor这样的概念的
//学生类有学号跟姓名的属性,有一个存着学生对象的vector容器,要使该容器按学号升序排序。
//学生类
Class CStudent:
{
public:
            CStudent(int iID, string strName)
        {m_iID=iID;  m_strName=strName; }
public:            
    int m_iID;
    string m_strName;
}

//学号比较函数
bool Compare(const CStudent &stuA,const CStudent &stuB)
{
         return (stuA.m_iID<strB.m_iID);
}

void main()
{
      vector<CStudent> vecStu;
      vecStu.push_back(CStudent(2,"老二"));
     vecStu.push_back(CStudent(1,"老大"));
     vecStu.push_back(CStudent(3,"老三"));
     vecStu.push_back(CStudent(4,"老四"));
      sort(vecStu.begin(),vecStu.end(),Compare);
//  此时,vecStu容器包含了按顺序的"老大对象","老二对象","老三对象","老四对象"
}

5.常用的拷贝和替换算法

  • copy: 复制序列

例如:vecIntA,vecIntB是用vector< int >声明的对象,vecIntA已包含1,3,5,7,9元素。
vecIntB.resize(5);
copy(vecIntA.begin(),vecIntA.end(),vecIntB.begin());
此时vecIntB也包含了1,3,5,7,9元素

  • replace(beg,end,oldValue,newValue): 将指定范围内的所有等于oldValue的元素替换成newValue
  • replace_if : 将指定范围内所有操作结果为true的元素用新值替换。

用法举例:
replace_if(vecIntA.begin(),vecIntA.end(),GreaterThree,newVal)
其中 vecIntA是用vector< int >声明的容器
GreaterThree 函数的原型是 bool GreaterThree(int iNum)

  • swap: 交换两个容器的元素

6.常用的算术与生成算法

  • accumulate: 对指定范围内的元素求和,然后结果再加上一个由val指定的初始值。
  • fill: 将输入值赋给标志范围内的所有元素。

7.常用的集合算法

  • set_union: 构造一个有序序列,包含两个有序序列的并集。
    set_intersection: 构造一个有序序列,包含两个有序序列的交集。
    set_difference: 构造一个有序序列,该序列保留第一个有序序列中存在而第二个有序序列中不存在的元素。

8.常用的遍历算法

  • for_each: 用指定函数依次对指定范围内所有元素进行迭代访问。该函数不得修改序列中的元素。
    transform: 与for_each类似,遍历所有元素,但可对容器的元素进行修改
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qiu931110/article/details/80691006
想对作者说点什么? 我来说一句

stl入门文档+讲义(C++

2010年12月19日 1.63MB 下载

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭