C++学习笔记(六):容器与算法

标准容器只是定义了一些基本的操作,也许用户还需要对顺序容器进行排序, 或者查找某个特定的元素, 或者查找最大或最小的元素。标准库对于这些潜在的操作并没有定义相关的成员函数,而是定义了相关的算法,这一组算法称为 泛型算法。

因为它们实现共同的操作,所以称之为 算法。 而泛型指的是 它们可以操作在多种容器类型上。  甚至某些内置数组或相关序列 以及 自定义的容器类型(只要与标准库兼容)同样可以使用这些泛型算法。

大多数算法一般是基于两个迭代器实现的。

概述:
举一个查找某一元素的例子

1  int 型的 vector 对象, 名为vec
  
  int search_value = 42;
  vector<int>:: const_iterator result = find(vec.begin(), vec.end(), search_value);

 2   list对象, lst
    list<int>::const_iterator result - find(ist.begin(), ist.end(), search_value);

由于指针的行为与作用在内置数组中的迭代器一样,因此也可以使用find来搜索数组:
     int ia[6]={27,  ..., };
 int  search_value =  83;
 int *result= find(ia, ia+6, search_value);


标准算法固有地独立于类型

这种算法,与容器的类型无关。但可能依赖元素类型,必须能够对元素做比较运算。其明确要求如下:

1 需要某种遍历集合的方式:能够从一个元素向前移动到下一个元素。
2 必须能够知道是否到达了集合的末尾。
3 必须能够对容器中的每一个元素与被查找的元素进行比较。
需要一个类型来指出元素在容器中的位置,或者表示找不到该元素。


  迭代器将算法和容器绑定起来
  泛型算法用迭代器来解决第一个要求: 遍历容器。  所有的迭代器都支持自增操作符。并提供解引用操作访问元素的值。

  迭代器用标记被查找的范围,第二个迭代器通常被称为 超出末端迭代器, 以此迭代器为返回值, 即可表示没有找到查找的元素。

算法从不基于容器操作 而是 基于迭代器操作,这是因为 基于迭代器的操作一般不会修改容器的内容
  
  标准库提供了100中算法。 与容器一样,算法有着一致的结构, 了解算法的设计能够使我们举一反三。


  什么是算法

使用泛型算法,必须包含  algorithm 头文件:
#include <algorithm>

标准库还定义了一组 泛化的 算术算法,其命名习惯与泛型算法相同。  使用这些算法则必须包含numeric头文件
#include <numeric>

理解算法的最基本方法是了解该算法是否读元素、写元素或者对元素进行重新排序。 

只读算法
这种算法, 只会读取输入范围内的元素,而不会写这些元素。 find就是一个这样的算法。
另一个简单的只读算法是 accumulate。  该算法在numeric头文件中定义:

它的形式为:  int sum = accumulate(vec.begin(), vec.end(), 0);
它表示对迭代器范围内的所有元素都进行累加并返回结果。
第三个参数非常有必要,它用于设定起始值,且与迭代器范围内的元素类型匹配。


find_first_of的使用

该函数使用两队迭代器参数来标记 两端元素范围, 在第一段范围内查找 与第二段范围中任意元素匹配的元素, 然后返回一个迭代器,指向第一个匹配的元素。如果找不到匹配的元素,则返回第一个范围的end迭代器

size_t cnt = 0;
list<string>::iterator it = roster1.begin();
while ((it = find_first_of(it, roster1.end(), roster2.begin(), roster2.end())) !=
roster1.end()) {
     ++ cnt;
     ++ it;

一对迭代器标记的必须是一个范围,且第一个迭代器必须不断的自增 以达到第二个迭代器的位置
当出现find_first_of这样的函数时, 每对迭代器中,两个实参的类型必须精确匹配,但不要求两队之间的类型匹配。 

写容器元素的算法
在使用一些算法写元素时 ,必须确保算法所写的序列至少足以存储要写入的元素。

写入输入序列的元素
写入到输入序列的算法本质上是安全的  只会写入与制定输入范围数量相同的元素。

fill(vec.begin(), vec.end(), 0);
vec为输入序列, 第三个参数为写入的值。

这种算法的好处是,它能够安全的写入到输入序列中

不检查写入操作的算法
  fill_n 函数带有的参数包括: 一个迭代器,一个计数器 和 一个值。 该函数从迭代器指向的元素开始,将制定数量的元素设置为给定的值。

 引入back_inserter (与fill_n的结合 将导致安全的操作)
确保算法有足够的元素 存储输出数据的一种方法是使用  插入迭代器。  插入迭代器是可以给 基础容器添加元素的迭代器。
使用back_inserter 的程序必须包含 iterator头文件

back_inserter是一个迭代器适配器,它使用一个对象作为实参,并生产一个适应期实参行为的新对象。

fill_n (back_inserter(vec), 10, 0);
这样,fill_n函数每写入一个值,都会通过back_inserter生成的插入迭代器实现。

fill_n是向输出数据序列 写入值, 其目标迭代器是 指向目标序列的第一个元素

写入目标迭代器的算法
  第三类算法向目标迭代器写入未知个数的元素, 正如fill_n函数一样,其目标迭代器也是指向目标序列的第一个元素。

  copy函数就是一个这样的简单算法:
  vector<int> ivec; // empty vector
  copy (ilist.begin(), ilist.end(), back_inserter(ivec));


算法的_copy版本
带有copy的算法,不会修改原序列的值,二回创建一个新的序列。
如replace算法,它就会修改序列。但是replace_copy会创建一个新的序列
 
replace(list.begin(), list.end(), 0, 42);
第三个参数 是list序列中的值, 第四个参数是要替换的值。

而replace_copy算法 需要接受5个参数:
replace(list.begin(), list.end(), back_inserter(ivec), 0, 42);


对容器元素重新排序的算法

例: 比如要统计 一本书里 出现的单词个数,并以单词的长度来输出,且同长度的单词以字典顺序输出。
则需要满足一下功能:
    1   需要将书本中的所有单词都存放在一个 vector的容器中
   2  对该容器  去除其重复的单词
   3  统计字母不小于六的单词
   4   对容器中的单词以字典顺序排序
   

   
   2   去除重复
      首先,应该用sort算法,对字典中的单词进行排序, 其格式为:
      sort(vec.begin(), vec.end());
      unique算法:
         它带有两个指定元素范围的迭代器参数。 该算法删除相邻的重复元素,然后重新排列输入范围内的元素,并且返回一个迭代器end_unique,表示无重复的值范围的结束。 即 将这个迭代器当做无重复范围的最后一个元素的下一个元素,也就是删除的重复的元素的第一个元素。 而删除的元素都是放在vector序列的最后面的
     以上算法并没有正在删除元素。如果想删除元素,还必须使用容器操作删除元素:
     
     使用容器操作删除元素:
        调用erase实现该功能。  从end_unique指向的元素开始删除。

     3  统计字母个数不小于六的单词
       为了解决该问题,需要调用stable_sort, count_if算法, 这两个算法都需要谓词函数作为第三个参数。
        谓词函数一般都是用is开头并返回bool型,提供了比较的约束的条件
        stable_sort的谓词函数可以定义为:
        bool isShorter( const string &s1, const string &s2)
         {
               return s1.size() <s2.size()
          }
       
       那么count_if的 谓词函数可以定义如下:
     bool isGT(const string &s1)
     {
            return s1.size()>=6;
     }
    
    4  最后按长度顺序输出
     可以用map  即  将word作为第一个参数, 将长度作为第二个参数
     然后按  第二个参数  进行sort排序 然后输出

    5 介绍: make_plural 
     这个是根据单词个数,觉得输出不同的字符串,即 是 单数还是复数:
     string make_plural(int size_t, string &s1, string &s2)
     {
          return (if(size<=1))? s1: s1+s2;
     }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值