日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STL详解

發(fā)布時間:2024/3/13 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STL详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

STL就是Standard Template Library,標準模板庫。這可能是一個歷史上最令人興奮的工具的最無聊的術(shù)語。從根本上說,STL是一些“容器”的集合,這些“容器”有list, vector,set,map等,STL也是算法和其它一些組件的集合。這里的“容器”和算法的集合指的是世界上很多聰明人很多年的杰作。是C++標準庫的一個重要組成部分,它由Stepanov and Lee等人最先開發(fā),它是與C++幾乎同時開始開發(fā)的;一開始STL選擇了Ada作為實現(xiàn)語言,但Ada有點不爭氣,最后他們選擇了C++,C++中已經(jīng)有了模板。STL又被添加進了C++庫。1996年,惠普公司又免費公開了STL,為STL的推廣做了很大的貢獻。STL提供了類型安全、高效而易用特性的STL無疑是最值得C++程序員驕傲的部分。每一個C++程序員都應(yīng)該好好學習STL。大體上包括container(容器)、algorithm(算法)和iterator(迭代器),容器和算法通過迭代器可以進行無縫連接。

?

一、基礎(chǔ)知識

1、泛型技術(shù)

泛型技術(shù)的實現(xiàn)方法有多種,比如模板,多態(tài)等。模板是編譯時決定,多態(tài)是運行時決定,其他的比如RTTI也是運行時確定。多態(tài)是依靠虛表在運行時查表實現(xiàn)的。比如一個類擁有虛方法,那么這個類的實例的內(nèi)存起始地址就是虛表地址,可以把內(nèi)存起始地址強制轉(zhuǎn)換成int*,取得虛表,然后(int*)*(int*)取得虛表里的第一個函數(shù)的內(nèi)存地址,然后強制轉(zhuǎn)換成函數(shù)類型,即可調(diào)用來驗證虛表機制。

泛型編程(generic programming,以下直接以GP稱呼)是一種全新的程序設(shè)計思想,和OO,OB,PO這些為人所熟知的程序設(shè)計想法不同的是GP抽象度更高,基于GP設(shè)計的組件之間偶合度底,沒有繼承關(guān)系,所以其組件間的互交性和擴展性都非常高。我們都知道,任何算法都是作用在一種特定的數(shù)據(jù)結(jié)構(gòu)上的,最簡單的例子就是快速排序算法最根本的實現(xiàn)條件就是所排序的對象是存貯在數(shù)組里面,因為快速排序就是因為要用到數(shù)組的隨機存儲特性,即可以在單位時間內(nèi)交換遠距離的對象,而不只是相臨的兩個對象,而如果用聯(lián)表去存儲對象,由于在聯(lián)表中取得對象的時間是線性的即O[n],這樣將使快速排序失去其快速的特點。也就是說,我們在設(shè)計一種算法的時候,我們總是先要考慮其應(yīng)用的數(shù)據(jù)結(jié)構(gòu),比如數(shù)組查找,聯(lián)表查找,樹查找,圖查找其核心都是查找,但因為作用的數(shù)據(jù)結(jié)構(gòu)不同將有多種不同的表現(xiàn)形式。數(shù)據(jù)結(jié)構(gòu)和算法之間這樣密切的關(guān)系一直是我們以前的認識。泛型設(shè)計的根本思想就是想把算法和其作用的數(shù)據(jù)結(jié)構(gòu)分離,也就是說,我們設(shè)計算法的時候并不去考慮我們設(shè)計的算法將作用于何種數(shù)據(jù)結(jié)構(gòu)之上。泛型設(shè)計的理想狀態(tài)是一個查找算法將可以作用于數(shù)組,聯(lián)表,樹,圖等各種數(shù)據(jù)結(jié)構(gòu)之上,變成一個通用的,泛型的算法。

2、四種類型轉(zhuǎn)換操作符

static_cast?????將一個值以符合邏輯的方式轉(zhuǎn)換。應(yīng)用到類的指針上,意思是說它允許子類類型的指針轉(zhuǎn)換為父類類型的指針(這是一個有效的隱式轉(zhuǎn)換),同時,也能夠執(zhí)行相反動作:轉(zhuǎn)換父類為它的子類。

例如:float x;

??????Count<<static_cast<int>(x);//把x作為整型值輸出

?

dynamic_cast??????????????將多態(tài)類型向下轉(zhuǎn)換為其實際靜態(tài)類型。只用于對象的指針和引用。當用于多態(tài)類型時,它允許任意的隱式類型轉(zhuǎn)換以及相反過程。dynamic_cast會檢查操作是否有效。也就是說,它會檢查轉(zhuǎn)換是否會返回一個被請求的有效的完整對象。檢測在運行時進行。如果被轉(zhuǎn)換的指針不是一個被請求的有效完整的對象指針,返回值為NULL.??????

例如:class Car;

?????????class Cabriolet:public Car{

?????????…

};

?????????class Limousline:public Car{

?????????…

};

?????????void f(Car *cp)

?????????{

??????????????Cabriolet *p = dynamic_cast< Cabriolet > cp;

}

?

reinterpret_cast???轉(zhuǎn)換一個指針為其它類型的指針。它也允許從一個指針轉(zhuǎn)換為整數(shù)類型。反之亦然。這個操作符能夠在非相關(guān)的類型之間轉(zhuǎn)換。操作結(jié)果只是簡單的從一個指針到別的指針的值的二進制拷貝。在類型之間指向的內(nèi)容不做任何類型的檢查和轉(zhuǎn)換。

例如:

class A {};
class B {};
A * a = new A;
B * b = reinterpret_cast<B *>(a);

?

const_cast一般用于強制消除對象的常量性。

例如:

class C {};
const C *a = new C;
C *b = const_cast<C *>(a);
其它三種操作符是不能修改一個對象的常量性的。

?

3、explicit修飾的構(gòu)造函數(shù)不能擔任轉(zhuǎn)換函數(shù)。在很多情況下,隱式轉(zhuǎn)換是有意的,并且是正當?shù)摹5袝r我們不希望進行這種自動的轉(zhuǎn)換。

例如:為了避免這樣的隱式轉(zhuǎn)換,應(yīng)該象下面這樣顯式聲明該帶單一參數(shù)的構(gòu)造函數(shù):

class String {
int size;
char *p;
//..
public:
?????? //?不要隱式轉(zhuǎn)換
?????? explicit String (int sz);?
?????? String (const char *s, int size n = 0); //?隱式轉(zhuǎn)換
};
void f ()
{
????String s(10);
????s = 100; //?現(xiàn)在編譯時出錯;需要顯式轉(zhuǎn)換:
????s = String(100); //?好;顯式轉(zhuǎn)換
????s = "st";????????//?好;此時允許隱式轉(zhuǎn)換
}

?

4、命名空間namespace

???解決在使用不同模塊和程序庫時,出現(xiàn)名稱沖突問題。

5、C++標準程序庫中的通用工具。由類和函數(shù)構(gòu)成。這些工具包括:

???數(shù)種通用類型

???一些重要的C函數(shù)

???數(shù)值極值

?

二、STL六大組件

容器(Container)

算法(Algorithm)

迭代器(Iterator)

仿函數(shù)(Function object)

適配器(Adaptor)

空間配置器(allocator)

1、容器

作為STL的最主要組成部分--容器,分為向量(vector),雙端隊列(deque),表(list),隊列(queue),堆棧(stack),集合(set),多重集合(multiset),映射(map),多重映射(multimap)。

容器

特性

所在頭文件

向量vector

可以用常數(shù)時間訪問和修改任意元素,在序列尾部進行插入和刪除時,具有常數(shù)時間復(fù)雜度,對任意項的插入和刪除就有的時間復(fù)雜度與到末尾的距離成正比,尤其對向量頭的添加和刪除的代價是驚人的高的

<vector>

雙端隊列deque

基本上與向量相同,唯一的不同是,其在序列頭部插入和刪除操作也具有常量時間復(fù)雜度

<deque>

表list

對任意元素的訪問與對兩端的距離成正比,但對某個位置上插入和刪除一個項的花費為常數(shù)時間。

<list>

隊列queue

插入只可以在尾部進行,刪除、檢索和修改只允許從頭部進行。按照先進先出的原則。

<queue>

堆棧stack

堆棧是項的有限序列,并滿足序列中被刪除、檢索和修改的項只能是最近插入序列的項。即按照后進先出的原則

<stack>

集合set

由節(jié)點組成的紅黑樹,每個節(jié)點都包含著一個元素,節(jié)點之間以某種作用于元素對的謂詞排列,沒有兩個不同的元素能夠擁有相同的次序,具有快速查找的功能。但是它是以犧牲插入刪除操作的效率為代價的

<set>

多重集合multiset

和集合基本相同,但可以支持重復(fù)元素具有快速查找能力

<set>

映射map

由{鍵,值}對組成的集合,以某種作用于鍵對上的謂詞排列。具有快速查找能力

<map>

多重集合multimap

比起映射,一個鍵可以對應(yīng)多了值。具有快速查找能力

<map>

STL容器能力表:

?

?

2、算法

算法部分主要由頭文件<algorithm>,<numeric>和<functional>組成。< algorithm>是所有STL頭文件中最大的一個,它是由一大堆模版函數(shù)組成的,可以認為每個函數(shù)在很大程度上都是獨立的,其中常用到的功能范 圍涉及到比較、交換、查找、遍歷操作、復(fù)制、修改、移除、反轉(zhuǎn)、排序、合并等等。<numeric>體積很小,只包括幾個在序列上面進行簡單數(shù)學運算的模板函數(shù),包括加法和乘法在序列上的一些操作。<functional>中則定義了一些模板類,用以聲明函數(shù)對象。

STL的算法也是非常優(yōu)秀的,它們大部分都是類屬的,基本上都用到了C++的模板來實現(xiàn),這樣,很多相似的函數(shù)就不用自己寫了,只要用函數(shù)模板就可以了。

我們使用算法的時候,要針對不同的容器,比如:對集合的查找,最好不要用通用函數(shù)find(),它對集合使用的時候,性能非常的差,最好用集合自帶的find()函數(shù),它針對了集合進行了優(yōu)化,性能非常的高。

?

3、迭代器

它的具體實現(xiàn)在<itertator>中,我們完全可以不管迭代器類是怎么實現(xiàn)的,大多數(shù)的時候,把它理解為指針是沒有問題的(指針是迭代器的一個特例,它也屬于迭代器),但是,決不能完全這么做。

迭代器功能

輸入迭代器

Input iterator

向前讀

Reads forward

istream

輸出迭代器

Output iterator

向前寫

Writes forward

ostream,inserter

前向迭代器

Forward iterator

向前讀寫

Read and Writes forward

?

雙向迭代器

Bidirectional iterator

向前向后讀寫

Read and Writes forward and

backward

list,set,multiset,map,mul

timap

隨機迭代器

Random access iterator

隨機讀寫

Read and Write with random

access

vector,deque,array,string

?

4、仿函數(shù)

仿函數(shù),又或叫做函數(shù)對象,是STL六大組件之一;仿函數(shù)雖然小,但卻極大的拓展了算法的功能,幾乎所有的算法都有仿函數(shù)版本。例如,查找算法find_if就是對find算法的擴展,標準的查找是兩個元素相等就找到了,但是什么是相等在不同情況下卻需要不同的定義,如地址相等,地址和郵編都相等,雖然這些相等的定義在變,但算法本身卻不需要改變,這都多虧了仿函數(shù)。仿函數(shù)(functor)又稱之為函數(shù)對象(function object),其實就是重載了()操作符的struct,沒有什么特別的地方。

如以下代碼定義了一個二元判斷式functor:

struct IntLess
{
bool operator()(int left, int right) const
{
?? return (left < right);
};
};

為什么要使用仿函數(shù)呢?

1).仿函數(shù)比一般的函數(shù)靈活。

2).仿函數(shù)有類型識別,可以作為模板參數(shù)。

3).執(zhí)行速度上仿函數(shù)比函數(shù)和指針要更快的。

怎么使用仿函數(shù)?

除了在STL里,別的地方你很少會看到仿函數(shù)的身影。而在STL里仿函數(shù)最常用的就是作為函數(shù)的參數(shù),或者模板的參數(shù)。

在STL里有自己預(yù)定義的仿函數(shù),比如所有的運算符,=,-,*,、比如'<'號的仿函數(shù)是less

template<class _Ty>
struct less?? : public binary_function<_Ty, _Ty, bool>
{ // functor for operator<
??????? bool operator()(const _Ty& _Left, const _Ty& _Right) const
?????????????????? { // apply operator< to operands
????????????????????????????? return (_Left < _Right);
?????????????????? }
};

從上面的定義可以看出,less從binary_function<...>繼承來的,那么binary_function又是什么的?

template<class _Arg1, class _Arg2, class _Result>
struct?binary_function
{ // base class for binary functions
??????? typedef _Arg1 first_argument_type;
???? ?? typedef _Arg2 second_argument_type;
????? typedef _Result result_type;

};

其實binary_function只是做一些類型聲明而已,別的什么也沒做,但是在STL里為什么要做這些呢?如果你要閱讀過STL的源碼,你就會發(fā)現(xiàn),這樣的用法很多,其實沒有別的目的,就是為了方便,安全,可復(fù)用性等。但是既然STL里面內(nèi)定如此了,所以作為程序員你必須要遵循這個規(guī)則,否則就別想安全的使用STL。

比如我們自己定一個仿函數(shù)。可以這樣:

template <typename type1,typename type2>
class func_equal :public binary_function<type1,type2,bool>
{
??????? inline bool operator()(type1 t1,type2 t2) const//這里的const不能少
??????????? {
???????????????? return t1 == t2;//當然這里要overload==

????????? ?? }
}

我們看這一行:?inline bool operator()(type1 t1,type2 t2) const//這里的const不能少
inline是聲明為內(nèi)聯(lián)函數(shù),我想這里應(yīng)該不用多說什么什么了,關(guān)鍵是為什么要聲明為const的?要想找到原因還是看源碼,加入如果我們這里寫一行代碼,find_if(s.begin(),s.end(),bind2nd(func_equal(),temp)),在bind2nd函數(shù)里面的參數(shù)是const類型的,const類型的對象,只能訪問cosnt修飾的函數(shù)!

與binary_function(二元函數(shù))相對的是unary_function(一元函數(shù)),其用法同binary_function

struct unary_function {?
typedef _A argument_type;?
typedef _R result_type;?
};

注:仿函數(shù)就是重載()的class,并且重載函數(shù)要為const的,如果要自定義仿函數(shù),并且用于STL接配器,那么一定要從binary_function或者,unary_function繼承。

?

5適配器

適配器是用來修改其他組件接口的STL組件,是帶有一個參數(shù)的類模板(這個參數(shù)是操作的值的數(shù)據(jù)類型)。STL定義了3種形式的適配器:容器適配器,迭代器適配器,函數(shù)適配器。

容器適配器:包括棧(stack)、隊列(queue)、優(yōu)先(priority_queue)。使用容器適配器,stack就可以被實現(xiàn)為基本容器類型(vector,dequeue,list)的適配。可以把stack看作是某種特殊的vctor,deque或者list容器,只是其操作仍然受到stack本身屬性的限制。queuepriority_queue與之類似。容器適配器的接口更為簡單,只是受限比一般容器要多。

迭代器適配器:修改為某些基本容器定義的迭代器的接口的一種STL組件。反向迭代器和插入迭代器都屬于迭代器適配器,迭代器適配器擴展了迭代器的功能。

函數(shù)適配器:通過轉(zhuǎn)換或者修改其他函數(shù)對象使其功能得到擴展。這一類適配器有否定器(相當于""操作)、綁定器、函數(shù)指針適配器。函數(shù)對象適配器的作用就是使函數(shù)轉(zhuǎn)化為函數(shù)對象,或是將多參數(shù)的函數(shù)對象轉(zhuǎn)化為少參數(shù)的函數(shù)對象。

例如:

在STL程序里,有的算法需要一個一元函數(shù)作參數(shù),就可以用一個適配器把一個二元函數(shù)和一個數(shù)值,綁在一起作為一個一元函數(shù)傳給算法。?
例如:?
find_if(coll.begin(), coll.end(), bind2nd(greater <int>(), 42));?
這句話就是找coll中第一個大于42的元素。?
greater <int>(),其實就是">"號,是一個2元函數(shù)?
bind2nd的兩個參數(shù),要求一個是2元函數(shù),一個是數(shù)值,結(jié)果是一個1元函數(shù)。
bind2nd就是個函數(shù)適配器。

?

6空間配置器

STL的內(nèi)存配置器在我們的實際應(yīng)用中幾乎不用涉及,但它卻在STL的各種容器背后默默做了大量的工作,STL內(nèi)存配置器為容器分配并管理內(nèi)存。統(tǒng)一的內(nèi)存管理使得STL庫的可用性、可移植行、以及效率都有了很大的提升。

SGI-STL的空間配置器有2種,一種僅僅對c語言的malloc和free進行了簡單的封裝,而另一個設(shè)計到小塊內(nèi)存的管理等,運用了內(nèi)存池技術(shù)等。在SGI-STL中默認的空間配置器是第二級的配置器。

SGI使用時std::alloc作為默認的配置器。

A).alloc把內(nèi)存配置和對象構(gòu)造的操作分開,分別由alloc::allocate()::construct()負責,同樣內(nèi)存釋放和對象析夠操作也被分開分別由alloc::deallocate()和::destroy()負責。這樣可以保證高效,因為對于內(nèi)存分配釋放和構(gòu)造析夠可以根據(jù)具體類型(type traits)進行優(yōu)化。比如一些類型可以直接使用高效的memset來初始化或者忽略一些析構(gòu)函數(shù)。對于內(nèi)存分配alloc也提供了2級分配器來應(yīng)對不同情況的內(nèi)存分配。

B).第一級配置器直接使用malloc()和free()來分配和釋放內(nèi)存。第二級視情況采用不同的策略:當需求內(nèi)存超過128bytes的時候,視為足夠大,便調(diào)用第一級配置器;當需求內(nèi)存小于等于128bytes的時候便采用比較復(fù)雜的memeory pool的方式管理內(nèi)存。

C).無論allocal被定義為第一級配置器還是第二級,SGI還為它包裝一個接口,使得配置的接口能夠符合標準即把配置單位從bytes轉(zhuǎn)到了元素的大小:

???????? ?????????template<class?T,?class?Alloc>

class?simple_alloc

{

public:

?????static?T*?allocate(size_t?n)

???? {

?????????return?0 ==?n?? 0 : (T*)Alloc::allocate(n?*?sizeof(T));

???? }

?

?????static?T*?allocate(void)

???? {

?????????return?(T*)?Alloc::allocate(sizeof(T));

???? }

?

?????static?void?deallocate(T*?p,?size_t?n)

???? {

?????????if?(0 !=?n)?Alloc::deallocate(p,?n?*?sizeof(T));

???? }

?

?????static?void?deallocate(T*?p)

???? {

?????????Alloc::deallocate(p,?sizeof(T));

???? }

}???

?

d).內(nèi)存的基本處理工具,它們均具有commt or rollback能力。

template<class?InputIterator,?class?ForwardIterator>

ForwardIterator

uninitialized_copy(InputIterator?first,?InputIterator?last,?ForwardIterator?result);

?

template<class?ForwardIterator,?class?T>

void?uninitialized_fill(ForwardIterator?first,?ForwardIterator?last,?const?T&?x);

?

template<class?ForwardIterator,?class?Size,?class?T>

ForwardIterator

uninitialized_fill_n(ForwardIterator?first,?ForwardIterator?last,?const?T&?x)

?

三、具體容器、算法

1、所有容器都提供了一個默認的構(gòu)造函數(shù),一個拷貝構(gòu)造函數(shù)。

例如:

list<int> l;

....

vector<int> ivector(l.begin(),l.end());

?

int array[]={1,2,3,4};

....

set<int> iset(array,array+sizeof(array)/sizeof(array[0]));

?

2、與大小相關(guān)的函數(shù)

size(),empty(),max_size()

3、返回迭代器的函數(shù)

begin(),end(),rbegin(),rend()

4、比較操作

==,!=,<,>,>=....

?

Vector詳解:

capacity(),返回vector能夠容納的元素個數(shù)。

size(),返回vector內(nèi)現(xiàn)有元素的個數(shù)。

賦值操作:

c1=c2; 把c2的全部元素指派給c1

c.assign(n,elem);復(fù)制n個elem,指派給c

c.assign(beg,end);將區(qū)間beg,end內(nèi)的元素指派給c

c1.swap(c2);將c1,c2元素互換

swap(c1,c2);同上

元素存取

c.at(index);

c[index];

c.front();返回第一個元素

c.back();

?

插入和刪除:

c.insert(pos.elem);

c.insert(pos,n.elem); 插入n個elem

c.insert(pos,beg,end); 在pos出插入beg,end區(qū)間內(nèi)的所有元素。

c.push_back(elem);

c.pop_back();

c.erase(pos); 刪除pos上的元素,返回下一個元素

c.erase(beg,end);

c.resize(num);將元素數(shù)量改為num,如果size變大了,多出來的新元素都要一default方式構(gòu)建。

c.resize(num,elem);將元素數(shù)量改為num,如果size變大了,多出來的新元素是elem的副本。

c.clear();刪除所有。

?

vector的reserve和resize

reserve只分配空間,而不創(chuàng)建對象,size()不變。而resize分配空間而且用空對象填充.

reserve是容器預(yù)留空間,但并不真正創(chuàng)建元素對象,在創(chuàng)建對象之前,不能引用容器內(nèi)的元素,因此當加入新的元素時,需要用push_back()/insert()函數(shù)。

resize是改變?nèi)萜鞯拇笮?#xff0c;并且創(chuàng)建對象,因此,調(diào)用這個函數(shù)之后,就可以引用容器內(nèi)的對象了,因此當加入新的元素時,用operator[]操作符,或者用迭代器來引用元素對象。

再者,兩個函數(shù)的形式是有區(qū)別的,reserve函數(shù)之后一個參數(shù),即需要預(yù)留的容器的空間;resize函數(shù)可以有兩個參數(shù),第一個參數(shù)是容器新的大小,第二個參數(shù)是要加入容器中的新元素,如果這個參數(shù)被省略,那么就調(diào)用元素對象的默認構(gòu)造函數(shù)。

vector有而deque無的:capacity(), reserve();

deque有而vector無的:push_front(elem), pop_front(); push_back(elem), pop_back();

STL提供的另兩種容器queue、stack,其實都只不過是一種adaptor,它們簡單地修飾deque的界面而成為另外的容器類型

?

List詳解:

for_each??(.begin(), .end(), “函數(shù)”);

count (.begin(), .end(), 100, jishuqi);

返回對象等于100的個數(shù)jishuqi值。

count_if() 帶一個函數(shù)對象的參數(shù)(上面“100”的這個參數(shù))。函數(shù)對象是一個至少帶有一個operator()方法的類。這個類可以更復(fù)雜。

find(*.begin().*end(),“要找的東西”);

如果沒有找到指出的對象,就會返回*.end()的值,要是找到了就返回一個指著找到的對象的iterator

fine_if();與count_if()類似,是find的更強大版本。

STL通用算法search()用來搜索一個容器,但是是搜索一個元素串,不象find()和find_if() 只搜索單個的元素。

search算法在一個序列中找另一個序列的第一次出現(xiàn)的位置。

search(A.begin(), A.end(), B.begin(), B.end());

在A中找B這個序列的第一次出現(xiàn)。

要排序一個list,我們要用list的成員函數(shù)sort(),而不是通用算法sort()。

list容器有它自己的sort算法,這是因為通用算法僅能為那些提供隨機存取里面元素 的容器排序。

list的成員函數(shù)push_front()和push_back()分別把元素加入到list的前面和后面。你可以使用insert() 把對象插入到list中的任何地方。

insert()可以加入一個對象,一個對象的若干份拷貝,或者一個范圍以內(nèi)的對象。

list成員函數(shù)pop_front()刪掉list中的第一個元素,pop_back()刪掉最后一個元素。函數(shù)erase()刪掉由一個iterator指出的元素。還有另一個erase()函數(shù)可以刪掉一個范圍的元素。

list的成員函數(shù)remove()用來從list中刪除元素。

*.remove("要刪除的對象");

通用算法remove()使用和list的成員函數(shù)不同的方式工作。一般情況下不改變?nèi)萜鞯拇笮 ?/p>

remove(*.begin(),*.end(),"要刪除的對象");

使用STL通用算法stable_partition()和list成員函數(shù)splice()來劃分一個list。

stable_partition()是一個有趣的函數(shù)。它重新排列元素,使得滿足指定條件的元素排在不滿足條件的元素前面。它維持著兩組元素的順序關(guān)系。

splice 把另一個list中的元素結(jié)合到一個list中。它從源list中刪除元素。

?

Set Map詳解:

STL map和set的使用雖不復(fù)雜,但也有一些不易理解的地方,如:

為何map和set的插入刪除效率比用其他序列容器高?

為何每次insert之后,以前保存的iterator不會失效?

為何map和set不能像vector一樣有個reserve函數(shù)來預(yù)分配數(shù)據(jù)?

當數(shù)據(jù)元素增多時(10000到20000個比較),map和set的插入和搜索速度變化如何?

C++ STL中標準關(guān)聯(lián)容器set, multiset, map, multimap內(nèi)部采用的就是一種非常高效的平衡檢索二叉樹:紅黑樹,也成為RB樹(Red-Black Tree)。RB樹的統(tǒng)計性能要好于一般的平衡二叉樹(AVL-樹).

為何map和set的插入刪除效率比用其他序列容器高?

大部分人說,很簡單,因為對于關(guān)聯(lián)容器來說,不需要做內(nèi)存拷貝和內(nèi)存移動。說對了,確實如此。map和set容器內(nèi)所有元素都是以節(jié)點的方式來存儲,其節(jié)點結(jié)構(gòu)和鏈表差不多,指向父節(jié)點和子節(jié)點。這里的一切操作就是指針換來換去,和內(nèi)存移動沒有關(guān)系。

為何每次insert之后,以前保存的iterator不會失效?(同解)

為何map和set不能像vector一樣有個reserve函數(shù)來預(yù)分配數(shù)據(jù)?

究其原理來說時,引起它的原因在于在map和set內(nèi)部存儲的已經(jīng)不是元素本身了,而是包含元素的節(jié)點。

其實你就記住一點,在map和set內(nèi)面的分配器已經(jīng)發(fā)生了變化,reserve方法你就不要奢望了。

當數(shù)據(jù)元素增多時(10000和20000個比較),map和set的插入和搜索速度變化如何?

如果你知道log2的關(guān)系你應(yīng)該就徹底了解這個答案。在map和set中查找是使用二分查找,也就是說,如果有16個元素,最多需要比較4次就能找到結(jié)果,有32個元素,最多比較5次。那么有10000個呢?最多比較的次數(shù)為log10000,最多為14次,如果是20000個元素呢?最多不過15次。

?

泛型算法:

所有算法的前兩個參數(shù)都是一對iterators:[first,last),用來指出容器內(nèi)一個范圍內(nèi)的元素。

每個算法的聲明中,都表現(xiàn)出它所需要的最低層次的iterator類型。

?

常用算法:

accumulate() 元素累加

adjacent_difference() 相鄰元素的差額

adjacent_find() 搜尋相鄰的重復(fù)元素

binary_search() 二元搜尋

copy() 復(fù)制

copy_backward() 逆向復(fù)制

count() 計數(shù)

count_if() 在特定條件下計數(shù)

equal() 判斷相等與否

equal_range() 判斷相等與否(傳回一個上下限區(qū)間范圍)

fill() 改填元素值

fill_n() 改填元素值,n 次

find() 搜尋

find_if() 在特定條件下搜尋

find_end() 搜尋某個子序列的最后一次出現(xiàn)地點

find_first_of() 搜尋某些元素的首次出現(xiàn)地點

for_each() 對范圍內(nèi)的每一個元素施行某動作

generate() 以指定動作的運算結(jié)果充填特定范圍內(nèi)的元素

generate_n() 以指定動作的運算結(jié)果充填 n 個元素內(nèi)容

includes() 涵蓋於

inner_product() 內(nèi)積

inplace_merge() 合并并取代(覆寫)

iter_swap() 元素互換

lexicographical_compare() 以字典排列方式做比較

lower_bound() 下限

max() 最大值

max_element() 最大值所在位置

min() 最小值

min_element() 最小值所在位置

merge() 合并兩個序列

mismatch() 找出不吻合點

next_permutation() 獲得下一個排列組合

泛型演算法(Generic Algorithms)與 Function Obje4 cts

nth_element() 重新安排序列中第n個元素的左右兩端

partial_sort() 局部排序

partial_sort_copy() 局部排序并復(fù)制到它處

partial_sum() 局部總和

partition() 切割

prev_permutation() 獲得前一個排列組合

random_shuffle() 隨機重排

remove() 移除某種元素(但不刪除)

remove_copy() 移除某種元素并將結(jié)果復(fù)制到另一個 container

remove_if() 有條件地移除某種元素

remove_copy_if() 有條件地移除某種元素并將結(jié)果復(fù)制到另一個 container

replace() 取代某種元素

replace_copy() 取代某種元素,并將結(jié)果復(fù)制到另一個 container

replace_if() 有條件地取代

replace_copy_if() 有條件地取代,并將結(jié)果復(fù)制到另一個 container

reverse() 顛倒元素次序

reverse_copy() 顛倒元素次序并將結(jié)果復(fù)制到另一個 container

rotate() 旋轉(zhuǎn)

rotate_copy() 旋轉(zhuǎn),并將結(jié)果復(fù)制到另一個 container

search() 搜尋某個子序列

search_n() 搜尋「連續(xù)發(fā)生 n 次」的子序列

set_difference() 差集

set_intersection() 交集

set_symmetric_difference() 對稱差集

set_union() 聯(lián)集

sort() 排序

stable_partition() 切割并保持元素相對次序

stable_sort() 排序并保持等值元素的相對次序

swap() 置換(對調(diào))

swap_range() 置換(指定范圍)

transform() 以兩個序列為基礎(chǔ),交互作用產(chǎn)生第三個序列

unique() 將重復(fù)的元素摺疊縮編,使成唯一

unique_copy() 將重復(fù)的元素摺疊縮編,使成唯一,并復(fù)制到他處

upper_bound() 上限

?

?

四、注意細節(jié):

1、auto_ptr?不能用new[]所生成的array作為初值,因為釋放內(nèi)存時用的是delete,而不是delete[]

2、就搜尋速度而言,hash table通常比二叉樹還要快5~10倍。hash table不是C++標準程序庫的一員。

3、迭代器使用過程中優(yōu)先選用前置式遞增操作符(++iter)而不是選擇后置式遞增操作符(iter++)。

3、迭代器三個輔助函數(shù):advance(),distance(),iter_swap()。

???????advance()可令迭代器前進

???????distance()可處理迭代器之間的距離。

???????iter_swap()可交換兩個迭代器所指內(nèi)容。

4、hasp函數(shù)?makeheap()、push_heap()、pop_heap()、sort_heap()

5、’/0’在string之中并不具有特殊意義,但是在一般C形式的string中卻用來標記字符串結(jié)束。在string中,字符?‘/0’和其他字符的地位完全相同。string中有三個函數(shù)可以將字符串內(nèi)容轉(zhuǎn)換成字符數(shù)組或C形式的string。

data()?????以字符數(shù)組的形式返回字符串內(nèi)容。但末未追加’/0’字符,返回類型并非有效的C形式string。

c_str()????以C形式返回字符串內(nèi)容(在末尾端添加’/0’字符)。

copy()????將字符串內(nèi)容復(fù)制到“調(diào)用者提供的字符數(shù)組”中,不添加’/0’字符。

6容器中用empty來代替檢查size是否為0;當使用new得到指針的容器時,切記在容器銷毀前delete那些指針;千萬不要把auto_ptr放入容器中。

7、盡量使用vectorstring來代替動態(tài)申請的數(shù)組;避免使用vector<bool>vector<bool>有兩個問題.第一,它不是一個真正STL容器,第二,它并不保存bool類型。

8、迭代器使用過程中,盡量使用iterator代替const_iteratorreverse_iteratorconst_reverse_iterator;使用distanceadvanceconst_iterators轉(zhuǎn)化成iterators

typedef deque<int> IntDeque;??// 和以前一樣

typedef IntDeque::iterator Iter;

typedef IntDeque::const_iterator ConstIter;

IntDeque??d;

ConstIter ci;

...?????// 讓ci指向d

Iter i(d.begin());????// 初始化i為d.begin()

advance(i, distance(i, ci));??// 調(diào)整i,指向ci位置

9、避免對setmultiset的鍵值進行修改。

10永遠讓比較函數(shù)對相同元素返回false。

11、排序選擇:

1)如果你需要在vector、string、deque或數(shù)組上進行完全排序,你可以使用sort或stable_sort。

2)如果你有一個vector、string、deque或數(shù)組,你只需要排序前n個元素,應(yīng)該用partial_sort。

3)如果你有一個vector、string、deque或數(shù)組,你需要鑒別出第n個元素或你需要鑒別出最前的n個元素,而不用知道它們的順序,nth_element是你應(yīng)該注意和調(diào)用的。

4)如果你需要把標準序列容器的元素或數(shù)組分隔為滿足和不滿足某個標準,你大概就要找partition或stable_partition。

5)如果你的數(shù)據(jù)是在list中,你可以直接使用partition和stable_partition,你可以使用list的sort來代替sort和stable_sort。如果你需要partial_sort或nth_element提供的效果,你就必須間接完成這個任務(wù)。
12、如果你真的想刪除東西的話就在類似remove的算法后接上erase。remove從一個容器中remove元素不會改變?nèi)萜髦性氐膫€數(shù),erase是真正刪除東西。
13、提防在指針的容器上使用類似remove的算法,在調(diào)用類似remove的算法前手動刪除和廢棄指針。
14、盡量用成員函數(shù)代替同名的算法,有些容器擁有和STL算法同名的成員函數(shù)。關(guān)聯(lián)容器提供了countfindlower_boundupper_boundequal_range,而list提供了removeremove_ifuniquesortmergereverse。大多數(shù)情況下,你應(yīng)該用成員函數(shù)代替算法。這樣做有兩個理由。首先,成員函數(shù)更快。其次,比起算法來,它們與容器結(jié)合得更好(尤其是關(guān)聯(lián)容器)。那是因為同名的算法和成員函數(shù)通常并不是是一樣的。
15
、容器中使用自定義的結(jié)構(gòu)體時,如果用到拷貝與賦值,結(jié)構(gòu)體需要重載operator=符號;比較容器分成相等與不等,相等時重載operator==符號,不等時重載operator<符號。比如set、map、multiset、multimap、priority_queue等容器類要求重載operator<符號。
16
Map/Multimap,Sets/Multisets都不能用push_back,push_front,因為它是自動排序的。

Set內(nèi)的相同數(shù)值的元素只能出現(xiàn)一次,Multisets內(nèi)可包含多個數(shù)值相同的元素。

Map內(nèi)的相同數(shù)值的元素只能出現(xiàn)一次,Multimap內(nèi)可包含多個數(shù)值相同的元素。內(nèi)部由二叉樹實現(xiàn),便于查找。

17、string 與 數(shù)字之間的轉(zhuǎn)換,轉(zhuǎn)換的方法有很多種,一般使用stringstream來實現(xiàn)轉(zhuǎn)換。比如:

#include??<iostream>

#include??<sstream>??

#include??<string>??

using???namespace???std;??

int???main()??

{??

??int???i=0;??

??string???temp;????

??stringstream???s;??

??//string轉(zhuǎn)換為數(shù)字

??temp = “1234”;?

??s<<temp;??

??s>>i;??

??cout<<i<<endl;??

?

?//數(shù)字轉(zhuǎn)換為string

?i=256;

?s<<i;

?temp = s.str();

?cout<<temp<<end;

?

?system("pause");??

?return???0;

}

?

18、對于自定義的結(jié)構(gòu)體,放入容器中,最好不要對容器進行內(nèi)存初始化(不要調(diào)用memset,zeromemory函數(shù)),否則如果結(jié)構(gòu)體中有指針類型的變量時,就會出現(xiàn)問題。

?

19Vector的函數(shù)泄漏問題

定義了一個

struct temp

{

?????char name[256];

?????int i;

}

Vector<temp> vect;

當對這個vect執(zhí)行pushback一些temp的結(jié)構(gòu)體后,執(zhí)行clear這樣是否會內(nèi)存泄露?可以釋放掉temp結(jié)構(gòu)體中的name內(nèi)存嗎?

解決方法:

不行,clear只是把那些元素全部刪除掉,并不是釋放內(nèi)存。再者,你這樣的定義容器是不需要釋放內(nèi)存的,如果你這樣定義,std::vector <temp> *pVec。就需要了。先pVec->clear()?pVec->swap( (std::vector <temp>)(*pVec) )。就能實現(xiàn)內(nèi)存的釋放。??

?

20、stl之map erase方法的正確使用
STL的map表里有一個erase方法用來從一個map中刪除掉指令的一個節(jié)點,不存在任何問題。
如果刪除多一個節(jié)點時,需要使用正確的調(diào)用方法。比如下面的方法是有問題:
for(ITER iter=mapTest.begin();iter!=mapTest.end();++iter)
{
cout<<iter->first<<":"<<iter->second<<endl;
mapTest.erase(iter);
}
這是一種錯誤的寫法,會導(dǎo)致程序行為不可知.究其原因是map 是關(guān)聯(lián)容器,對于關(guān)聯(lián)容器來說,如果某一個元素已經(jīng)被刪除,那么其對應(yīng)的迭代器就失效了,不應(yīng)該再被使用;否則會導(dǎo)致程序無定義的行為。

正確的使用方法:
1).使用刪除之前的迭代器定位下一個元素。STL建議的使用方式
for(ITER iter=mapTest.begin();iter!=mapTest.end();)
{
cout<<iter->first<<":"<<iter->second<<endl;
mapTest.erase(iter++);
}

或者
for(ITER iter=mapTest.begin();iter!=mapTest.end();)
{
ITER iterTmp = iter;
iter++;
cout<<iterTmp->first<<":"<<iterTmp->second<<endl;
mapTest.erase(iterTmp);
}

2). erase() 成員函數(shù)返回下一個元素的迭代器
for(ITER iter=mapTest.begin();iter!=mapTest.end();)
{
cout<<iter->first<<":"<<iter->second<<endl;
iter=mapTest.erase(iter);
}

?21、boost::bind總結(jié)?
bind 是一組重載的函數(shù)模板.用來向一個函數(shù)(或函數(shù)對象)綁定某些參數(shù). bind的返回值是一個函數(shù)對象.?
性質(zhì):
不是函數(shù),是一個class,是一個多元仿函數(shù)

模板參數(shù):
帶模板參數(shù),但不需要,會自動推導(dǎo)!

構(gòu)造函數(shù)參數(shù):
格式:_需要綁定類型,_參數(shù)1,_參數(shù)2,_參數(shù)3,_參數(shù)4…

_需要綁定類型:可以是普通函數(shù),類成員函數(shù),成員變量

_參數(shù)N:可以是一個占位符,或者實際參數(shù)。

如果綁定的類型是一個類成員函數(shù)或變量,那么第一個參數(shù)必須是對象或者對象指針。
仿函數(shù)參數(shù):
任意

仿函數(shù)返回值
?????? 如果綁定的是函數(shù),返回綁定函數(shù)的返回值。

?????? 如果綁定是成員變量,返回成員變量值

占位符:
_1,_2,_3,_4….._9

占位符的數(shù)字表示仿函數(shù)時對應(yīng)參數(shù)的位置。

一個bind里可以嵌入多個bind,但占位符是相對于這一塊的bind是共享。

注意事項
a)如果綁定的是類函數(shù),傳入對象時,最好使用對象指針,如果使用對象實例會產(chǎn)生多次對象復(fù)制。如果非要傳對象而不想多次被復(fù)制傳在在使用ref或cref(ref的const版)

b)?跟lambda混用時一定要特別小心

第一、?? 會與lambda的占位符有沖突

第二、?? lambda庫里有跟同樣名字的bind,功能類似,但沒有此功能強大

總結(jié)
無模板參數(shù),構(gòu)函數(shù)對綁定函數(shù)負責,仿函數(shù)是任意的。

?

舉例說明
例一:


void nine_arguments(

?????????????????????? int i1,int i2,int i3,int i4,

?????????????????????? int i5,int i6,int i7,int i8, int i9) {

??????????????????????????? std::cout << i1 << i2 << i3 << i4 << i5

???????????????????????????????? << i6 << i7 << i8 << i9 << '/n';

}

?

int main() {

???? int i1=1,i2=2,i3=3,i4=4,i5=5,i6=6,i7=7,i8=8,i9=9;

???? (boost::bind(&nine_arguments,_9,_2,_1,_6,_3,_8,_4,_5,_7))

???????? (i1,i2,i3,i4,i5,i6,i7,i8,i9);

}
輸出結(jié)果921638457

?

推薦書籍:

《C++標準程序庫》本書將焦點放在標準模板庫(Standard Template Library)身上,檢驗其中的容器(containers)、迭代器(iterators)、仿函數(shù)(functors)和算法(algorithms)。你還可以找到特殊容器、字符串(strings)、數(shù)值類別、國際化議題、IOStream。每一個組件都有深刻的呈現(xiàn),包括其介紹、設(shè)計、運用實例、細部解說、陷阱、意想不到的危險,以及相關(guān)類別和函數(shù)的確切標記(signature)和定義。一份見解深刻的基礎(chǔ)概念介紹和一個程序庫綜合鳥瞰,會對新手帶來快速的提升。

《泛型編程與STL》闡述了泛型程序設(shè)計的中心觀念:concepts,modeling, refinement,并為你展示這些觀念如何導(dǎo)出?STL?的基礎(chǔ)概念:iterators, containers, function objects.循此路線,你可以把?STL?想象為一個由?concepts(而非明確之?functions?classes)組成的?library.你將學習其正式結(jié)構(gòu)并因此獲得其潛在威力之完整優(yōu)勢.

《Effective STL》闡述了如何有效地使用STLStandard Template Library,?標準模板庫)進行編程。書中講述了如何將STL組件組合在一起,從而利用庫的設(shè)計。這些內(nèi)容會幫助你針對簡單的問題開發(fā)出簡單、直接的解決方案,并且針對復(fù)雜的問題開發(fā)出精致的解決方案。書中還描述了常見的STL使用錯誤,并告訴你如何避免這些錯誤。

《STL源碼剖析》了解源碼,看到vector的實現(xiàn)、list的實現(xiàn)、heap的實現(xiàn)、deque的實現(xiàn)、RB-tree的實現(xiàn)、hash-table的實現(xiàn)、set/map?的實現(xiàn);你將看到各種算法(排序、搜尋、排列組合、數(shù)據(jù)移動與復(fù)制)的實現(xiàn);你甚至將看到底層的memory pool?和高階抽象的traits?機制的實現(xiàn)。

STL China?網(wǎng)站:http://www.stlchina.org/

總結(jié)

以上是生活随笔為你收集整理的STL详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。