博览网:STL与泛型编程第四周笔记

简书地址:

1、算法

基本的C++算法分为三类:排序算法、树算法、图算法

算法思想有三种:递推、分治、动态规划 以及 贪心算法。

本节课程中总结:Algorithms看不见Containers,对其一无所知;所以它需要的一切信息都必须从Iterators取得,而Iterators(由Containers供应)必须能够回答Algorithm的所有提问,才能搭配该Algorithm的所有操作。

一般STL中的算法都是以下两种形式(其中的Algorithm是一种泛指,可以替代其他的函数名称)

template

Algorithm (Iterator itr1, Iterator itr2)

{

..........

}

template

Algorithm (Iterator itr1, Iterator itr2, Cmp comp)

{

..........

}

因为算法对容器的操作必须通过迭代器来进行,在进行算法的讨论之前有必要对迭代器进行分类。

1.1迭代器的分类

Iterator(迭代器)模式又称Cursor(游标)模式,用于提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。或者这样说可能更容易理解:Iterator模式是运用于聚合对象的一种模式,通过运用该模式,使得我们可以在不知道对象内部表示的情况下,按照一定顺序(由iterator提供的方法)访问聚合对象中的各个元素。

由于Iterator模式的以上特性:与聚合对象耦合,在一定程度上限制了它的广泛运用,一般仅用于底层聚合支持类,如STL的list、vector、stack等容器类及ostream_iterator等扩展iterator。

迭代器由容器来提供,各种容器的Iterators的5种iterator_category如下:

除了output_iterator_tag,其余四个之间是继承关系。

1.2各种容器迭代器的打印

(1)通过iterator_traits可以将容器传入的迭代器区分出种类:

(2)通过使用typeid函数来实现迭代器类型的打印:

1.3iterator_category对算法的影响

前面说过算法需要迭代器的信息;而不同的算法对于不同的对象进行操作的时候,往往需要根据具体的情况处理。因此,在标准库中,我们表面上看到的算法都是接收迭代器就可以了,实际上算法在与操作对象的交流中早就知道了迭代器的类型,并且根据这个类型做出了不同的判断。这个判断的过程,一般是通过traits来实现的。

为了实现上述的思想,算法的结构可以大致表现为两个部分:

主函数部分,作为对外接口

次函数部分,作为对各种不同迭代器的分情况处理

下面以具体的例子进行说明。

(1)distance函数

distance函数用于计算两个迭代器之间的距离,具体的源代码如下:

[cpp] view plain copy print?

template

inline iterator_traits::difference_type

_distance(InputIterator first, InputIterator last, input_iterator_tag) {

iterator_traits::difference_type = 0;

while (first != last) {

++ first;

++ n;

}

return n;

}

template

inline iterator_traits::difference_type

_distance(RandomAccessIterator first, RandomAccessIterator last,

random_access_iterator_tag) {

return last - first;

}

//--------------------------------------

template

inline iterator_traits::difference_type

distance(InputIterator first, InputIterator last) {

typedef typename

iterator_traits::iterator_category category;

return _distance(first, last, category());

从上图可以看出,主函数distance接收两个迭代器,返回两个迭代器之间的距离。在实现过程中主函数调用了名为_distance的次函数;该次函数需要指定迭代器的类型。主函数通过iterator_traits对接收的迭代器InputIterator的类型进行判断,然后选择正确的次函数进行距离的计算。

主函数有两个参数,次函数比主函数多一个参数,第三个参数category()由iterator_traits判断出迭代器的种类后return给次函数,从而根据迭代器的类型选择不同的次函数。

(2)advance函数

advance函数的流程与distance函数的大同小异,具体如下图所示:

(3)copy函数

copy函数针对不同类型的Iterator进行了详细的区分和判断,选择最高效的方法来完成复制。

(4)destroy函数

destroy函数和copy函数类似,也对不同类型的Iterator进行了详细的区分和判断,选择最高效的方法来完成操作。

具体源代码及示意图如下所示:

(5)unique_copy函数

unique_copy()与之前的实现方法类似,但是要注意的一个地方是这个函数可以接受一个OutputIterator类型的迭代器作为其参数,OutputIterator类型迭代器的一个重要特点是:只写(write only)。具体如下图所示:

1.4算法对iterator_category的暗示

算法源代码对迭代器的类型并没有语法上的规定,但是会有暗示,具体如下图所示:

算法的效率与能否判断出iterator的分类有着重要的关系。算法源代码中对iterator_category都是采用暗示的方式,因为算法主要为模版函数,而模版函数可以传入任何的类型,所以只是定义模版的时候定义为需要的迭代器名字,但并不是真正的区分类型。如果传入的类型不正确,编译会不通过,采用这样的方式来区分iterator的类型。

1.5相关算法分析

(1)算法accumulate

(2)算法for_each

(3)算法replace,replace_if , replace_copy

(4)算法count, count_if

(4)算法find、find_if

(5)算法sort

2.仿函数Functors

按照功能的不同,仿函数可分为算术类、逻辑类和关系类三种,具体如下图所示:

标准库提供的functors都继承了binary_function

template

struct binary_function {

typedef Arg1 first_argument_type;

typedef Arg2 second_argument_type;

typedef Result result_type;

}

继承binary_function的意义在于,告诉算法传进来的是二元运算。仿函数在传递进算法的时候,需要告诉算法两个参与运算的类型,以及一个用于接受结果的类型。

如果没有继承,在某些场合也可以使用,但是当我们需要修改或者适配它本身的时候很可能就会出问题。

3.适配器Adapter

适配器按照类型的不同,可分为容器适配器、迭代器适配器和仿函数适配器三种,具体如下图所示:

3.1容器适配器

容器适配器:stack、queue

template >

class stack{

//.......

public:

typedef typename Squence::value_type value_type;

typedef typename Squence::size_type size_type;

typedef typename Squence::reference reference;

typedef typename Squence::const_reference const_reference;

protected:

Sequence c;  //底层容器

public:

bool empty() const {return c.empty();}

size_type size() const {return c.size();}

reference top() {return c.back();}

const_reference top() const {return c.back();}

void push (const value_type& x) { c.push_back(x);}

void pop() {c.pop_back();}

}

template  >

class queue{

//.............

public:

typedef typename Squence::value_type value_type;

typedef typename Squence::size_type size_type;

typedef typename Squence::reference reference;

typedef typename Squence::const_reference const_reference;

protected:

Sequence c;  //底层容器

public:

bool empty() const {return c.empty();}

size_type size() const {return c.size();}

reference front() {return c.front();}

const_reference front() const {return c.front();}

reference back() {return c.back();}

const_reference back() const {return c.back();}

void push (const value_type& x) { c.push_back(x);}

void pop() {c.pop_front();}

}

3.2函数适配器

函数适配器:binder2nd

函数适配器:not1

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容