目录
2.1 各种容器的迭代器的iterator_category(迭代器的种类)
2.2 通过typeid()可以获取iterator_category
(3)replace(), replace_if()和replace_copy()
1 算法的形式
C++标椎库的算法,是什么东西?
- 算法实际上看不到容器,它通过迭代器来进行运算。算法通过询问迭代器(之前有说迭代器需要提供的五个相关类型)来完成自己的工作。
- 算法在语言层面是是一个函数模板,具体是一个仿函数。具有类似以下的格式:
template <typename Iterator>
std::Algorithm(Iterator itr1, Iterator itr2, ......)
{
......
}
2 迭代器的分类(category)
2.1 各种容器的迭代器的iterator_category(迭代器的种类)
一共有五种iterator_category,它们的关系如图所示:
iterator_category | 简述 | 容器 |
---|---|---|
forward_iterator_tag | 仅单向前进 | forward_list,unordered_set,unordered_map,unordered_multiset,unordered_multimap |
bidirectional_iterator_tag | 双向,允许前进和后退 | list,set,map,multiset,multimap |
random_access_iterator_tag | 允许访问随机下标 | array,vector,deque |
另外有两种比较特殊,他们各自仅包含了一种迭代器
iterator_category | 包含的迭代器 |
---|---|
input_iterator_tag | istream_iterator |
output_iterator_tag | ostream_iterator |
2.2 通过typeid()可以获取iterator_category
//---------------------------------------------------
#include <iostream> // std::cout
#include <iterator> // std::iterator_traits
#include <typeinfo> // typeid
namespace jj33
{
void _display_category(random_access_iterator_tag)
{ cout << "random_access_iterator" << endl; }
void _display_category(bidirectional_iterator_tag)
{ cout << "bidirectional_iterator" << endl; }
void _display_category(forward_iterator_tag)
{ cout << "forward_iterator" << endl; }
void _display_category(output_iterator_tag)
{ cout << "output_iterator" << endl; }
void _display_category(input_iterator_tag)
{ cout << "input_iterator" << endl; }
template<typename I>
void display_category(I itr)
{
typename iterator_traits<I>::iterator_category cagy;
_display_category(cagy);
cout << "typeid(itr).name()= " << typeid(itr).name() << endl << endl;
//The output depends on library implementation.
//The particular representation pointed by the
//returned valueis implementation-defined,
//and may or may not be different for different types.
}
void test_iterator_category()
{
cout << "\ntest_iterator_category().......... \n";
display_category(array<int,10>::iterator());
display_category(vector<int>::iterator());
display_category(list<int>::iterator());
display_category(forward_list<int>::iterator());
display_category(deque<int>::iterator());
display_category(set<int>::iterator());
display_category(map<int,int>::iterator());
display_category(multiset<int>::iterator());
display_category(multimap<int,int>::iterator());
display_category(unordered_set<int>::iterator());
display_category(unordered_map<int,int>::iterator());
display_category(unordered_multiset<int>::iterator());
display_category(unordered_multimap<int,int>::iterator());
display_category(istream_iterator<int>());
display_category(ostream_iterator<int>(cout,""));
}
}
可以注意到这些打印出来的iterator_category名称前后有一些无规律字符和数字,这些是编译器中的库实现方法决定的,编译器不同,这些数据也不同。但是实际上为了符合C++标准,它的实际类型都是一样的。
3 迭代器分类(category)对算法的影响的四个实例
3.1 distance
用来计算两个迭代器之间的距离。
3.2 advance(和distance近似)
和distance的做法基本相同,advance代表前进n步。
3.3 copy
拷贝函数。
- copy用了很多次泛化和特化,除了iterator traits以外还用了type traits。
- copy对其template参数所要求的条件非常宽松。其输入区间只需由inputIterators构成即可,输出区间只需要由OutputIterator构成即可。这意味着可以使用copy算法,将任何容器的任何一段区间的内容,复制到任何容器的任何一段区间上。
3.4 destory(和copy近似,略)
摧毁一个对象,调用析构函数。
3.5 迭代器的特殊情况_unique_copy
4 算法对迭代器中iterator_category的暗示
由于算法必须接受所有的迭代器,但是算法本身可以选择不对其进行处理。对于这些算法不想处理的迭代器,算法会在源代码中进行一些暗示。
比如说这里就是特意修改了模板参数名,来暗示使用者这个算法的适用范围。
5 算法源代码剖析(11个例子)
5.1 如何判断是C的算法还是C++中的算法?
5.2 十一个算法实例
(1)accumulate()
accumulate()是累计函数,默认是加,也可以传入自定义操作.
template <class InputIterator,
class T>
T accumulate(InputIterator first,
InputIterator last,
T init)
{
for( ; first != last; ++first)
// 将元素累加到初始值init身上
init = init + *first;
return init;
}
template <class InputIterator,
class T,
class BinaryOperation>
T accumulate(InputIterator first,
InputIterator last,
T init,
BinaryOperation binary_op)
{
for( ; first != last; ++first)
// 将元素【累计算】到初始值init身上
init = binary_op(init, *first);
return init;
}
(2)for_each()
对一个范围内的元素做某种操作.
template <class InputIterator,
class Function>
Function for_each(InputIterator first,
InputIterator last,
Function f)
{
for( ; first != last; ++first)
f(*first);
return f;
}
该函数会返回一个值,但这个返回值会被忽略。还要注意不能通过迭代器修改元素的值,因为输入的是InputIterator,只读不能写。
(3)replace(), replace_if()和replace_copy()
- replace() 算法会用新的值来替换和给定值相匹配的元素。它的前两个参数是被处理序列的正向迭代器,第 3 个参数是被替换的值,第 4 个参数是新的值。
- replace_if() 会将使谓词返回 true 的元素替换为新的值。它的第 3 个参数是一个谓词,第 4 个参数是新的值。参数的类型一般是元素类型的 const 引用;const 不是强制性的,但谓词不应该改变元素。
- replace_copy() 算法和 replace() 做的事是一样的,但它的结果会被保存到另一个序列中,而不会改变原始序列。它的前两个参数是输入序列的正向迭代器,第 3 个参数是输入序列的开始迭代器,最后两个参数分别是要被替换的值和替换值。
template <class ForwardIterator, class T>
void replace(ForwardIterator first,
ForwardIterator last,
const T& old_value,
const T& new_value){
//范围内所有等同于old_value者都以new_value取代
for(; first != last; ++first)
if(*first == old_value)
*first = new_value;
}
template <class ForwardIterator, class Predicate, class T>
void replace_if(ForwardIterator first,
ForwardIterator last,
Predicate pred,
const T& new_value){
//范围内所有满足pred()为true者都以new_value取代
for(; first != last; ++first)
if(pred(*first))
*first = new_value;
}
template <class ForwardIterator, class OutputIterator, class T>
OutputIterator replace_copy(ForwardIterator first,
ForwardIterator last,
OutputIterator result,
const T& old_value,
const T& new_value){
//范围内所有等同于old_value者都以new_value放到新区间,不符合者原值放到新区间
for(; first != last; ++first, ++result)
*result =
*first == old_value ? new_value : *first;
return result;
}
(4)count()和count_if()
- count函数统计元素个数,返回一个整形变量
- count_if函数按条件统计元素个数
template <class InputIterator, class T>
typename iterator_traits<InputIterator>::difference_type
count(InputIterator first, InputIterator last,
const T& value)
{
typename iterator_traits<InputIterator>::difference_type n = 0;
for(; first != last; ++first)
if(*first == value)
++n;
return n;
}
template <class InputIterator, class Predicate>
typename iterator_traits<InputIterator>::difference_type
count_if(InputIterator first, InputIterator last,
Predicate pred)
{
typename iterator_traits<InputIterator>::difference_type n = 0;
for(; first != last; ++first)
if(pred(*first))
++n;
return n;
}
(5)find()和find_if()
- find() 函数本质上是一个模板函数,用于在指定范围内查找和目标元素值相等的第一个元素。
- find_if() 函数和 find() 函数相同,find_if() 函数也用于在指定区域内执行查找操作。不同的是,前者需要明确指定要查找的元素的值,而后者则允许自定义查找规则。
template <class InputIterator, class T>
InputIterator find(InputIterator first,
InputIterator last,
const T& value)
{
while(first != last && *first != value)
++first;
return first;
}
template <class InputIterator, class Predicate>
InputIterator find_if(InputIterator first,
InputIterator last,
Predicate pred)
{
while(first != last && !pred(*first))
++first;
return first;
}
(6)sort()
只介绍了sort()的用法。
#include <iostream> // std::cout
#include <algorithm> // std::sort
#include <vector> // std::vector
namespace jj36
{
bool myfunc (int i,int j) { return (i<j); }
struct myclass {
bool operator() (int i,int j) { return (i<j);}
} myobj;
bool test_sort()
{
cout << "\ntest_sort().......... \n";
int myints[] = {32,71,12,45,26,80,53,33};
vector<int> myvec(myints, myints+8); // 32 71 12 45 26 80 53 33
// using default comparison (operator <):
sort(myvec.begin(), myvec.begin()+4); //(12 32 45 71)26 80 53 33
// using function as comp
sort(myvec.begin()+4, myvec.end(), myfunc); // 12 32 45 71(26 33 53 80)
// using object as comp
sort(myvec.begin(), myvec.end(), myobj); //(12 26 32 33 45 53 71 80)
// print out content:
cout << "\nmyvec contains:";
for (auto elem : myvec) //C++11 range-based for statement
cout << ' ' << elem ; //output: 12 26 32 33 45 53 71 80
// using reverse iterators and default comparison (operator <):
sort(myvec.rbegin(), myvec.rend());
// print out content:
cout << "\nmyvec contains:";
for (auto elem : myvec) //C++11 range-based for statement
cout << ' ' << elem ; //output: 80 71 53 45 33 32 26 12
// using explicitly default comparison (operator <):
sort(myvec.begin(), myvec.end(), less<int>());
// print out content:
cout << "\nmyvec contains:";
for (auto elem : myvec) //C++11 range-based for statement
cout << ' ' << elem ; //output: 12 26 32 33 45 53 71 80
// using another comparision criteria (operator >):
sort(myvec.begin(), myvec.end(), greater<int>());
// print out content:
cout << "\nmyvec contains:";
for (auto elem : myvec) //C++11 range-based for statement
cout << ' ' << elem ; //output: 80 71 53 45 33 32 26 12
}
}
逆向迭代器:
包含了一点rbegin()和rend()的内容,逆向迭代器的实现以后会讲。
(7)binary_search()
用二分查找判断有序序列中是否存在某元素,内部工作是交给lower_bound()去做的。
template <class ForwardIterator, class T>
bool binary_search(ForwardIterator first,
ForwardIterator last,
const T& val)
{
first = std::lower_bound(first, last, val);
return (first != last && !(val < *first));
}
template <class ForwardIterator, class T>
ForwardIterator
lower_bound(ForwardIterator first,
ForwardIterator last,
const T& val)
{
ForwardIterator it;
iterator_traits<ForwardIterator>::difference_type count, step;
count = distance(first, last);
while(count > 0)
{
it = first; step = count / 2; advance(it, step);
if(*it < val){
first = ++it;
count -= step + 1;
}
else count = step;
}
return first;
}
简单介绍一下lower_bound()和upper_bound():
- 以从小到大排列的序列为例,lower_bound()返回的是第一个大于等于target的元素的位置,也就是第一个可以合法地插入target的位置;
- upper_bound()返回的是第一个大于target的元素,也就是最后一个可以合法地插入target的位置。当然都可能出现target不存在的情况,这时返回的要么是begin()要么是end(),然后再进行一下和头元素或尾元素的大小判断就能知道target是否存在了。