当前位置:编程学习 > C/C++ >>

C++学习笔记(四) 通用算法

正如STL为我们封装了很多数据结构一样,STL同样也为我们提供了很多通用算法,例如排序,查找等。这些算法本身实际上就是一种函数模板,它不依赖与具体的类型,而是通过迭代器和模板来实现的。对于通用算法,这里有一个重要的概念,那就是:算法绝不执行Container操作,它只会使用迭代器来执行它的逻辑,永远不会直接的去调用容器本身的函数。如果我们为算法提供的是原始迭代器,那么算法就绝不会改变底层容器的大小。

STL提供的算法库很庞大,要记下这么多的算法是很困难的,所幸它几乎所有的算法都遵循如下的结构形式:

[cpp] 
alg (beg, end, other parms); 
alg (beg, end, dest, other parms); 
alg (beg, end, beg2, other parms); 
alg (beg, end, beg2, end2, other parms); 

其中,像beg,end,beg2,end2,dest之类的参数都是指迭代器。
要学习STL的算法,我们还是从最基本的查询算法开始,它的声明形式如下:

[cpp] 
template <class InputIterator, class T> 
          InputIterator find ( InputIterator first, InputIterator last, const T& value ); 

可以看出,find函数属于第一类通用算法,它的作用是在前两个参数所规定的序列范围内查找值等于value的元素,并返回其迭代器。这个版本的find函数要求其元素类型必须支持==或!=操作符。
对于查找算法,STL提供的还有find_first_of(和string::find_first_of的用法类似),find_if等等。

接下来是说下排序算法,STL所提供的排序算法要求的迭代器类型都必须是随机迭代器(可以参考我的上一篇笔记)。下表列出了STL所提供的排序算法:

函数名

功能描述

sort

对给定区间所有元素进行排序

stable_sort

对给定区间所有元素进行稳定排序

partial_sort

对给定区间所有元素部分排序

partial_sort_copy

对给定区间复制并排序

nth_element

找出给定区间的某个位置对应的元素

is_sorted

判断一个区间是否已经排好序

partition

使得符合某个条件的元素放在前面

stable_partition

相对稳定的使得符合某个条件的元素放在前面


其中,有stable修饰的函数表示该排序算法是稳定的,即对于相等的元素,不改变它的原始序列。

以sort为例,看一下它的声明形式:
[cpp] 
template <class RandomAccessIterator> 
         void sort ( RandomAccessIterator first, RandomAccessIterator last );                                                                 
template <class RandomAccessIterator, class Compare> 
         void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp ); 

first和last这两个迭代器限定了排序的范围,第一个版本要求基本元素类型必须支持<运算符,而在第二个版本中,则显示的通过第三个参数传递比较函数,用于进行排序时的比较。其他排序算法的声明形式大多和此类似,这里就不做赘述,具体可参考帮助文档。
然后,我们来关注一下累加算法。先看它的声明形式:

[cpp] 
template <class InputIterator, class T> 
          T accumulate ( InputIterator first, InputIterator last, T init ); 
template <class InputIterator, class T, class BinaryOperation> 
          T accumulate ( InputIterator first, InputIterator last, T init, 
                         BinaryOperation binary_op ); 

同样,根据同样算法的一般形式,前两个参数规定了一个序列范围,这个范围内的元素都将被累加起来,但三个参数指出了累加的初始值。第一个版本需要元素本身支持加法操作,而第二个版本还有第四个参数,这个参数可以传递一个函数对象,它提供两个基本元素的相加操作。需要注意的是,由于该函数模板的实例化是根据第三个参数而来的,因此在传递第三个参数时,我们需要格外小心使它的类型与前两者的元素类型保持一致。下面的例子就是一个容易出错的典范:

[cpp] 
//v is a vector<double> 
accumulate<v.begin(), v.end(), 0); 

我们的本意是累加一个double型的容器,结果,在传递初始值时传递了0而不是0.0,那么accumulate函数模板就被实例化为一个int型的实例,结果造成了意料外的精度损失。
C语言中有这么一个函数memset,它可以对一片内存区连续的填充值,在STL里也提供了一些类似的函数,不过它们更加抽象,其作用对象时容器,而非实际的物理内存区。这些函数大多以fill开头。需要注意的是,其中一些填充函数的使用并不是很安全,需要程序员自己去保证容器的容量足够大。例如,下面关于对fill_n函数的使用就是不安全的:

[cpp] 
vector<int> vec; // empty vector 
// disaster: attempts to write to 10 (nonexistent) elements in vec 
fill_n(vec.begin(), 10, 0); 

fill_n函数并不会帮你去检查你说指定的容器是否有足够大的空间容纳这些元素,而只是进行简单的填充。所以,我们常常使用back_inserter来在容器后面安全的插入元素。
[cpp] 
vector<int> vec; // empty vector 
// ok: back_inserter creates an insert iterator that adds elements to vec 
fill_n (back_inserter(vec), 10, 0); // appends 10 elements to vec 

back_inserter函数模板返回的是一个迭代器适配器,类似于container adapter,它将封装一个容器,并产生一个新的对象,这个对象可以作为迭代器来使用,每次通过这个迭代器进行写操作都会隐式的调用容器的push_back函数从而在容器的最后插入新值。
插入迭代器适配器主要有三种,它们的写操作对应调用的容器操作如下:

back_inserter push_back
front_inserter push_front
inserter insert
前面说过,使用普通迭代器的通用算法绝不会改变容器的大小,所以要想对容器进行插入操作,必须使用这些插入迭代器适配器。
下面再简单列举一下常用的算法的声明形式,具体使用请查阅帮助文档。

剔除容器中重复的元素,该函数要求重复元素必须是连续的:

[cpp] 
template <class ForwardIterator> 
         ForwardIterator unique ( ForwardIterator first, ForwardIterator last ); 
template <class ForwardIterator, class BinaryPredicate> 
         ForwardIterator unique ( ForwardIterator first, ForwardIterator last, 
                                  BinaryPredicate pred ); 

对容器内容进行拷贝:
[cpp] 
template <class InputIterator, class OutputIterator> 
         OutputIterator copy ( InputIterator first, InputIterator last, OutputIterator result ); 

替换容器中指定的元素:
[cpp] 
template < class ForwardIterator, class T > 
         void replace ( ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value ); 

拷贝内容到另一容器并替换掉指定的元素(该函数并不会改变原来的容器);
[cpp] 
template < class InputIterator, class OutputIterator, class T >  www.zzzyk.com
         OutputIterator replace_copy ( InputIterator first, InputIterator last, OutputIterator result, const T& old_value, const T& new_value );  

计算容器中满足条件的元素的个数:
[cpp] 
template <class InputIterator, class Predicate> 
         typename iterator_traits<InputIterator>::difference_type 
           count_if ( ForwardItera

补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,