博覽網(wǎng):STL與泛型編程第四周筆記

簡書地址:

1、算法

基本的C++算法分為三類:排序算法、樹算法、圖算法

算法思想有三種:遞推、分治、動態(tài)規(guī)劃 以及 貪心算法。

本節(jié)課程中總結:Algorithms看不見Containers,對其一無所知;所以它需要的一切信息都必須從Iterators取得,而Iterators(由Containers供應)必須能夠回答Algorithm的所有提問,才能搭配該Algorithm的所有操作。

一般STL中的算法都是以下兩種形式(其中的Algorithm是一種泛指,可以替代其他的函數(shù)名稱)

template

Algorithm?(Iterator?itr1,?Iterator?itr2)

{

..........

}

template

Algorithm?(Iterator?itr1,?Iterator?itr2,?Cmp?comp)

{

..........

}

因為算法對容器的操作必須通過迭代器來進行,在進行算法的討論之前有必要對迭代器進行分類。

1.1迭代器的分類

Iterator(迭代器)模式又稱Cursor(游標)模式,用于提供一種方法順序訪問一個聚合對象中各個元素, 而又不需暴露該對象的內(nèi)部表示。或者這樣說可能更容易理解:Iterator模式是運用于聚合對象的一種模式,通過運用該模式,使得我們可以在不知道對象內(nèi)部表示的情況下,按照一定順序(由iterator提供的方法)訪問聚合對象中的各個元素。

由于Iterator模式的以上特性:與聚合對象耦合,在一定程度上限制了它的廣泛運用,一般僅用于底層聚合支持類,如STL的list、vector、stack等容器類及ostream_iterator等擴展iterator。

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

除了output_iterator_tag,其余四個之間是繼承關系。

1.2各種容器迭代器的打印

(1)通過iterator_traits可以將容器傳入的迭代器區(qū)分出種類:

(2)通過使用typeid函數(shù)來實現(xiàn)迭代器類型的打印:

1.3iterator_category對算法的影響

前面說過算法需要迭代器的信息;而不同的算法對于不同的對象進行操作的時候,往往需要根據(jù)具體的情況處理。因此,在標準庫中,我們表面上看到的算法都是接收迭代器就可以了,實際上算法在與操作對象的交流中早就知道了迭代器的類型,并且根據(jù)這個類型做出了不同的判斷。這個判斷的過程,一般是通過traits來實現(xiàn)的。

為了實現(xiàn)上述的思想,算法的結構可以大致表現(xiàn)為兩個部分:

主函數(shù)部分,作為對外接口

次函數(shù)部分,作為對各種不同迭代器的分情況處理

下面以具體的例子進行說明。

(1)distance函數(shù)

distance函數(shù)用于計算兩個迭代器之間的距離,具體的源代碼如下:

[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());

從上圖可以看出,主函數(shù)distance接收兩個迭代器,返回兩個迭代器之間的距離。在實現(xiàn)過程中主函數(shù)調用了名為_distance的次函數(shù);該次函數(shù)需要指定迭代器的類型。主函數(shù)通過iterator_traits對接收的迭代器InputIterator的類型進行判斷,然后選擇正確的次函數(shù)進行距離的計算。

主函數(shù)有兩個參數(shù),次函數(shù)比主函數(shù)多一個參數(shù),第三個參數(shù)category()由iterator_traits判斷出迭代器的種類后return給次函數(shù),從而根據(jù)迭代器的類型選擇不同的次函數(shù)。

(2)advance函數(shù)

advance函數(shù)的流程與distance函數(shù)的大同小異,具體如下圖所示:

(3)copy函數(shù)

copy函數(shù)針對不同類型的Iterator進行了詳細的區(qū)分和判斷,選擇最高效的方法來完成復制。

(4)destroy函數(shù)

destroy函數(shù)和copy函數(shù)類似,也對不同類型的Iterator進行了詳細的區(qū)分和判斷,選擇最高效的方法來完成操作。

具體源代碼及示意圖如下所示:

(5)unique_copy函數(shù)

unique_copy()與之前的實現(xiàn)方法類似,但是要注意的一個地方是這個函數(shù)可以接受一個OutputIterator類型的迭代器作為其參數(shù),OutputIterator類型迭代器的一個重要特點是:只寫(write only)。具體如下圖所示:

1.4算法對iterator_category的暗示

算法源代碼對迭代器的類型并沒有語法上的規(guī)定,但是會有暗示,具體如下圖所示:

算法的效率與能否判斷出iterator的分類有著重要的關系。算法源代碼中對iterator_category都是采用暗示的方式,因為算法主要為模版函數(shù),而模版函數(shù)可以傳入任何的類型,所以只是定義模版的時候定義為需要的迭代器名字,但并不是真正的區(qū)分類型。如果傳入的類型不正確,編譯會不通過,采用這樣的方式來區(qū)分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.仿函數(shù)Functors

按照功能的不同,仿函數(shù)可分為算術類、邏輯類和關系類三種,具體如下圖所示:

標準庫提供的functors都繼承了binary_function

template

struct?binary_function?{

typedef?Arg1?first_argument_type;

typedef?Arg2?second_argument_type;

typedef?Result?result_type;

}

繼承binary_function的意義在于,告訴算法傳進來的是二元運算。仿函數(shù)在傳遞進算法的時候,需要告訴算法兩個參與運算的類型,以及一個用于接受結果的類型。

如果沒有繼承,在某些場合也可以使用,但是當我們需要修改或者適配它本身的時候很可能就會出問題。

3.適配器Adapter

適配器按照類型的不同,可分為容器適配器、迭代器適配器和仿函數(shù)適配器三種,具體如下圖所示:

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函數(shù)適配器

函數(shù)適配器:binder2nd

函數(shù)適配器:not1

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容