學(xué)無止境!!!
第一部分:(參考百度百科)
一、STL簡介
STL(Standard Template Library,標(biāo)準(zhǔn)模板庫)是惠普實(shí)驗(yàn)室開發(fā)的一系列軟件的統(tǒng)稱。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普實(shí)驗(yàn)室工作時(shí)所開發(fā)出來
的。現(xiàn)在雖說它主要出現(xiàn)在C++中,但在被引入C++之前該技術(shù)就已經(jīng)存在了很長的一段時(shí)間。
STL的代碼從廣義上講分為三類:algorithm(算法)、container(容器)和iterator(迭代器),幾乎所有的代碼都采用了模板類和模版函數(shù)的方式,這相比于傳統(tǒng)的由函數(shù)和類
組成的庫來說提供了更好的代碼重用機(jī)會。在C++標(biāo)準(zhǔn)中,STL被組織為下面的13個(gè)頭文件:<algorithm>、<deque>、<functional>、<iterator>、<vector>、<list>、<map>、
<memory>、<numeric>、<queue>、<set>、<stack>和<utility>。
二、算法
大家都能取得的一個(gè)共識是函數(shù)庫對數(shù)據(jù)類型的選擇對其可重用性起著至關(guān)重要的作用。舉例來說,一個(gè)求方根的函數(shù),在使用浮點(diǎn)數(shù)作為其參數(shù)類型的情況下的可重用性肯定比
使用整型作為它的參數(shù)類性要高。而C++通過模板的機(jī)制允許推遲對某些類型的選擇,直到真正想使用模板或者說對模板進(jìn)行特化的時(shí)候,STL就利用了這一點(diǎn)提供了相當(dāng)多的有用
算法。它是在一個(gè)有效的框架中完成這些算法的——你可以將所有的類型劃分為少數(shù)的幾類,然后就可以在模版的參數(shù)中使用一種類型替換掉同一種類中的其他類型。
STL提供了大約100個(gè)實(shí)現(xiàn)算法的模版函數(shù),比如算法for_each將為指定序列中的每一個(gè)元素調(diào)用指定的函數(shù),stable_sort以你所指定的規(guī)則對序列進(jìn)行穩(wěn)定性排序等等。這樣一來
,只要我們熟悉了STL之后,許多代碼可以被大大的化簡,只需要通過調(diào)用一兩個(gè)算法模板,就可以完成所需要的功能并大大地提升效率。
算法部分主要由頭文件<algorithm>,<numeric>和<functional>組成。
<algorithm>是所有STL頭文件中最大的一個(gè)(盡管它很好理解),它是由一大堆模版函數(shù)組成的,可以認(rèn)為每個(gè)函數(shù)在很大程度上都是獨(dú)立的,其中常用到的功能范圍涉及到比較、交換、查找、遍歷操作、復(fù)制、修改、移除、反轉(zhuǎn)、排序、合并等等。
<numeric>體積很小,只包括幾個(gè)在序列上面進(jìn)行簡單數(shù)學(xué)運(yùn)算的模板函數(shù),包括加法和乘法在序列上的一些操作。
<functional>中則定義了一些模板類,用以聲明函數(shù)對象。
三、容器
在實(shí)際的開發(fā)過程中,數(shù)據(jù)結(jié)構(gòu)本身的重要性不會遜于操作于數(shù)據(jù)結(jié)構(gòu)的算法的重要性,當(dāng)程序中存在著對時(shí)間要求很高的部分時(shí),數(shù)據(jù)結(jié)構(gòu)的選擇就顯得更加重要。
經(jīng)典的數(shù)據(jù)結(jié)構(gòu)數(shù)量有限,但是我們常常重復(fù)著一些為了實(shí)現(xiàn)向量、鏈表等結(jié)構(gòu)而編寫的代碼,這些代碼都十分相似,只是為了適應(yīng)不同數(shù)據(jù)的變化而在細(xì)節(jié)上有所出入。STL容器
就為我們提供了這樣的方便,它允許我們重復(fù)利用已有的實(shí)現(xiàn)構(gòu)造自己的特定類型下的數(shù)據(jù)結(jié)構(gòu),通過設(shè)置一些模版類,STL容器對最常用的數(shù)據(jù)結(jié)構(gòu)提供了支持,這些模板的參數(shù)
允許我們指定容器中元素的數(shù)據(jù)類型,可以將我們許多重復(fù)而乏味的工作簡化。
容器部分主要由頭文件<vector>,<list>,<deque>,<set>,<map>,<stack>和<queue>組成。對于常用的一些容器和容器適配器(可以看作由其它容器實(shí)現(xiàn)的容器),可以通過下表總結(jié)一下它們和相應(yīng)頭文件的對應(yīng)關(guān)系。
向量(vector)連續(xù)存儲的元素<vector>
列表(list) 由節(jié)點(diǎn)組成的雙向鏈表,每個(gè)結(jié)點(diǎn)包含著一個(gè)元素<list>
雙隊(duì)列(deque)連續(xù)存儲的指向不同元素的指針?biāo)M成的數(shù)組<deque>
集合(set)由節(jié)點(diǎn)組成的紅黑樹,每個(gè)節(jié)點(diǎn)都包含著一個(gè)元素,節(jié)點(diǎn)之間以某種作用于元素對的謂詞排列,沒有兩個(gè)不同的元素能夠擁有相同的次序 <set>
多重集合(multiset)允許存在兩個(gè)次序相等的元素的集合 <set>
棧(stack)后進(jìn)先出的值的排列 <stack>
隊(duì)列(queue)先進(jìn)先出的執(zhí)的排列 <queue>
優(yōu)先隊(duì)列(PRiority_queue)元素的次序是由作用于所存儲的值對上的某種謂詞決定的的一種隊(duì)列 <queue>
映射(map)由{鍵,值}對組成的集合,以某種作用于鍵對上的謂詞排列 <map>
多重映射(multimap)允許鍵對有相等的次序的映射 <map>
四、迭代器
下面要說的迭代器從作用上來說是最基本的部分,可是理解起來比前兩者都要費(fèi)力一些(至少筆者是這樣)。軟件設(shè)計(jì)有一個(gè)基本原則,所有的問題都可以通過引進(jìn)一個(gè)間接層來
簡化,這種簡化在STL中就是用迭代器來完成的
。
概括來說,迭代器在STL中用來將算法和容器聯(lián)系起來,起著一種黏和劑的作用。幾乎STL提供的所有算法都是通過迭代器存取元素序列進(jìn)行工作的,每一個(gè)容器都定義了其本身所專有的迭代器,用以存取容器中的元素。
迭代器部分主要由頭文件<utility>,<iterator>和<memory>組成。
<utility>是一個(gè)很小的頭文件,它包括了貫穿使用在STL中的幾個(gè)模板的聲明,
<iterator>中提供了迭代器使用的許多方法,而對于<memory>的描述則十分的困難,它以不同尋常的方式為容器中的元素分配存儲空間,同時(shí)也為某些算法執(zhí)行期間產(chǎn)生的臨時(shí)對象提供機(jī)制,<memory>中的主要部分是模板類allocator,它負(fù)責(zé)產(chǎn)生所有容器中的默認(rèn)分配器。
對于之前不太了解STL的讀者來說,上面的文字只是十分概括地描述了一下STL的框架,對您理解STL的機(jī)制乃至使用STL所起到的幫助微乎甚微,這不光是因?yàn)樯钊隨TL需要對C++的高級應(yīng)用有比較全面的了解,更因?yàn)镾TL的三個(gè)部分算法、容器和迭代器三部分是互相牽制或者說是緊密結(jié)合的。從概念上講最基礎(chǔ)的部分是迭代器,可是直接學(xué)習(xí)迭代器會遇到許多抽象枯燥和繁瑣的細(xì)節(jié),然而不真正理解迭代器又是無法直接進(jìn)入另兩部分的學(xué)習(xí)的(至少對剖析源碼來說是這樣)。可以說,適應(yīng)STL處理問題的方法是需要花費(fèi)一定的時(shí)間的,但是以此為代價(jià),STL取得了一種十分可貴的獨(dú)立性,它通過迭代器能在盡可能少地知道某種數(shù)據(jù)結(jié)構(gòu)的情況下完成對這一結(jié)構(gòu)的運(yùn)算,所以下決心鉆研STL的朋友們千萬不要被一時(shí)的困難擊倒。其實(shí)STL運(yùn)用的模式相對統(tǒng)一,只要適應(yīng)了它,從一個(gè)STL工具到另一個(gè)工具,都不會有什么大的變化。
對于STL的使用,也普遍存在著兩種觀點(diǎn)。第一種認(rèn)為STL的最大作用在于充當(dāng)經(jīng)典的數(shù)據(jù)結(jié)構(gòu)和算法教材,因?yàn)樗脑创a涉及了許多具體實(shí)現(xiàn)方面的問題。第二種則認(rèn)為STL的初衷乃是為了簡化設(shè)計(jì),避免重復(fù)勞動(dòng),提高編程效率,因此應(yīng)該是“應(yīng)用至上”的,對于源代碼則不必深究。筆者則認(rèn)為分析源代碼和應(yīng)用并不矛盾,通過分析源代碼也能提高我們對其應(yīng)用的理解,當(dāng)然根據(jù)具體的目的也可以有不同的側(cè)重。
第二部分:
暫且舉幾個(gè)非常容易理解的程序源碼:
#include <iostream>#include <vector>using namespace std;int main(){ vector<int>vi; int a; while(true) { cout<<"輸入一個(gè)整數(shù),按0停止輸入:"; cin>>a; if(a==0) break; vi.push_back(a); vector<int>::iterator iter; for(iter=vi.begin();iter!=vi.end();++iter) cout<<*iter; } return 0; }
#include <iostream> #include <string>#include <vector> using namespace std; int main(){string str="shiyang"; vector <string> vecstr; vecstr.push_back(str);vector <string> ::iterator iter= vecstr.begin(); cout<<*iter<<endl;return 0;}
#include <stdlib.h> #include <windows.h> #include <conio.h> #include <map> //STL#include <functional> //STL #include <algorithm> //STL#include <iostream> using namespace std; typedef map<int,int*> m_iip; typedef map<int,char*> m_icp; class f_c{ int _i; public: f_c(int i):_i(i){ } void Operator()(m_iip::value_type ite) { cout<<_i++<<"/t"<<ite.first<<" shi"<<endl; } void operator()(m_icp::value_type ite) { cout<<_i++<<"/t"<<ite.first<<" yang"<<endl; } }; void f(int i,int c) { } int main(int argc,char* argv[]){ m_iip iip; m_icp icp; int i=0; iip.insert(make_pair(34,&i)); iip.insert(make_pair(67,&i)); iip.insert(make_pair(5,&i)); iip.insert(make_pair(342,&i)); char d=0; icp.insert(make_pair(12,&d)); icp.insert(make_pair(54,&d)); icp.insert(make_pair(6,&d)); icp.insert(make_pair(92,&d)); for_each(iip.begin(),iip.end(),f_c(8)); for_each(icp.begin(),icp.end(),f_c(65));// return 0; }
#include <iostream>#include <list>#include <numeric>#include <algorithm>using namespace std;//創(chuàng)建一個(gè)list容器的實(shí)例LISTINTtypedef list<int> LISTINT;//創(chuàng)建一個(gè)list容器的實(shí)例LISTCHARtypedef list<int> LISTCHAR;int main(){ //-------------------------- //用list容器處理整型數(shù)據(jù) //-------------------------- //用LISTINT創(chuàng)建一個(gè)名為listOne的list對象 LISTINT listOne; //聲明i為迭代器 LISTINT::iterator i; //從前面向listOne容器中添加數(shù)據(jù) listOne.push_front (2); listOne.push_front (1); //從后面向listOne容器中添加數(shù)據(jù) listOne.push_back (3); listOne.push_back (4); //從前向后顯示listOne中的數(shù)據(jù) cout<<"listOne.begin()--- listOne.end():"<<endl; for (i = listOne.begin(); i != listOne.end(); ++i) cout << *i << " "; cout << endl; //從后向前顯示listOne中的數(shù)據(jù)LISTINT::reverse_iterator ir; cout<<"listOne.rbegin()---listOne.rend():"<<endl; for (ir =listOne.rbegin(); ir!=listOne.rend();ir++) { cout << *ir << " "; } cout << endl; //使用STL的accumulate(累加)算法 int result = accumulate(listOne.begin(), listOne.end(),0); cout<<"Sum="<<result<<endl; cout<<"------------------"<<endl; //-------------------------- //用list容器處理字符型數(shù)據(jù) //-------------------------- //用LISTCHAR創(chuàng)建一個(gè)名為listOne的list對象 LISTCHAR listTwo; //聲明i為迭代器 LISTCHAR::iterator j; //從前面向listTwo容器中添加數(shù)據(jù) listTwo.push_front ('A'); listTwo.push_front ('B'); //從后面向listTwo容器中添加數(shù)據(jù) listTwo.push_back ('x'); listTwo.push_back ('y'); //從前向后顯示listTwo中的數(shù)據(jù) cout<<"listTwo.begin()---listTwo.end():"<<endl; for (j = listTwo.begin(); j != listTwo.end(); ++j) cout << char(*j) << " "; cout << endl; //使用STL的max_element算法求listTwo中的最大元素并顯示 j=max_element(listTwo.begin(),listTwo.end()); cout << "The maximum element in listTwo is: "<<char(*j)<<endl;}
#include <iostream>#include <list>using namespace std;typedef list<int> INTLIST;//從前向后顯示list隊(duì)列的全部元素void put_list(INTLIST list, char *name){ INTLIST::iterator plist; cout << "The contents of " << name << " : "; for(plist = list.begin(); plist != list.end(); plist++) cout << *plist << " "; cout<<endl;}//測試list容器的功能int main(){//list1對象初始為空 INTLIST list1; //list2對象最初有10個(gè)值為6的元素 INTLIST list2(10,6); //list3對象最初有9個(gè)值為6的元素 INTLIST list3(list2.begin(),--list2.end()); //聲明一個(gè)名為i的雙向迭代器 INTLIST::iterator i; //從前向后顯示各list對象的元素 put_list(list1,"list1"); put_list(list2,"list2"); put_list(list3,"list3"); //從list1序列后面添加兩個(gè)元素list1.push_back(2);list1.push_back(4);cout<<"list1.push_back(2) and list1.push_back(4):"<<endl; put_list(list1,"list1");//從list1序列前面添加兩個(gè)元素list1.push_front(5);list1.push_front(7);cout<<"list1.push_front(5) and list1.push_front(7):"<<endl; put_list(list1,"list1");//在list1序列中間插入數(shù)據(jù)3個(gè)9 list1.insert(++list1.begin(),3,9);cout<<"list1.insert(list1.begin(),3,9):"<<endl; put_list(list1,"list1");//測試引用類函數(shù)cout<<"list1.front()="<<list1.front()<<endl;cout<<"list1.back()="<<list1.back()<<endl;//從list1序列的前后各移去一個(gè)元素list1.pop_front();list1.pop_back();cout<<"list1.pop_front() and list1.pop_back():"<<endl; put_list(list1,"list1");//清除list1中的第2個(gè)元素list1.erase(++list1.begin());cout<<"list1.erase(++list1.begin()):"<<endl; put_list(list1,"list1");//對list2賦值并顯示list2.assign(8,1);cout<<"list2.assign(8,1):"<<endl; put_list(list2,"list2");//顯示序列的狀態(tài)信息cout<<"list1.max_size(): "<<list1.max_size()<<endl;cout<<"list1.size(): "<<list1.size()<<endl;cout<<"list1.empty(): "<<list1.empty()<<endl;//list序列容器的運(yùn)算 put_list(list1,"list1"); put_list(list3,"list3");cout<<"list1>list3: "<<(list1>list3)<<endl;cout<<"list1<list3: "<<(list1<list3)<<endl;//對list1容器排序list1.sort(); put_list(list1,"list1"); //結(jié)合處理list1.splice(++list1.begin(), list3); put_list(list1,"list1"); put_list(list3,"list3"); }
第三部分:
50條忠告:(其中有幾條覺得寫的不夠貼切,所以刪了,發(fā)了余下的部分)
1.把C++當(dāng)成一門新的語言學(xué)習(xí);
2.看《Thinking In C++》,不要看《C++變成死相》;
3.看《The C++ Programming Language》和《Inside The C++ Object Model》,不要因?yàn)樗麄兒茈y而我們自己是初學(xué)者所以就不看;
4.不要被VC、BCB、BC、MC、TC等詞匯所迷惑——他們都是集成開發(fā)環(huán)境,而我們要學(xué)的是一門語言;
5.不要放過任何一個(gè)看上去很簡單的小編程問題——他們往往并不那么簡單,或者可以引伸出很多知識點(diǎn);
6.會用Visual C++,并不說明你會C++;
7.學(xué)class并不難,template、STL、generic programming也不過如此——難的是長期堅(jiān)持實(shí)踐和不遺余力的博覽群書;
8.如果不是天才的話,想學(xué)編程就不要想玩游戲——你以為你做到了,其實(shí)你的C++水平并沒有和你通關(guān)的能力一起變高——其實(shí)可以時(shí)刻記住:學(xué)C++是為了編游戲的;
9.看Visual C++的書,是學(xué)不了C++語言的;
16.把時(shí)髦的技術(shù)掛在嘴邊,還不如把過時(shí)的技術(shù)記在心里;
18.學(xué)習(xí)編程最好的方法之一就是閱讀源代碼;
19.在任何時(shí)刻都不要認(rèn)為自己手中的書已經(jīng)足夠了;
20.請閱讀《The Standard C++ Bible》(中文版:標(biāo)準(zhǔn)C++寶典),掌握C++標(biāo)準(zhǔn);
21.看得懂的書,請仔細(xì)看;看不懂的書,請硬著頭皮看;
22.別指望看第一遍書就能記住和掌握什么——請看第二遍、第三遍;
23.請看《Effective C++》和《More Effective C++》以及《Exceptional C++》;
24.不要停留在集成開發(fā)環(huán)境的搖籃上,要學(xué)會控制集成開發(fā)環(huán)境,還要學(xué)會用命令行方式處理程序;
25.和別人一起討論有意義的C++知識點(diǎn),而不是爭吵XX行不行或者YY與ZZ哪個(gè)好;
26.請看《程序設(shè)計(jì)實(shí)踐》,并嚴(yán)格的按照其要求去做;
27.不要因?yàn)镃和C++中有一些語法和關(guān)鍵字看上去相同,就認(rèn)為它們的意義和作用完全一樣;
28.C++絕不是所謂的C的“擴(kuò)充”——如果C++一開始就起名叫Z語言,你一定不會把C和Z語言聯(lián)系得那么緊密;
29.請不要認(rèn)為學(xué)過XX語言再改學(xué)C++會有什么問題——你只不過又在學(xué)一門全新的語言而已;
30.讀完了《Inside The C++ Object Model》以后再來認(rèn)定自己是不是已經(jīng)學(xué)會了C++;
31.學(xué)習(xí)編程的秘訣是:編程,編程,再編程;
32.請留意下列書籍:《C++面向?qū)ο蟾咝Ь幊蹋–++ Effective Object-Oriented Software Construction)》《面向?qū)ο筌浖?gòu)造(Object-Oriented Software Construction)》《設(shè)計(jì)模式(Design Patterns)》《The Art of Computer Programming》;
34.請把書上的程序例子親手輸入到電腦上實(shí)踐,即使配套光盤中有源代碼;
35.把在書中看到的有意義的例子擴(kuò)充;
36.請重視C++中的異常處理技術(shù),并將其切實(shí)的運(yùn)用到自己的程序中;
37.經(jīng)常回顧自己以前寫過的程序,并嘗試重寫,把自己學(xué)到的新知識運(yùn)用進(jìn)去;
38.不要漏掉書中任何一個(gè)練習(xí)題——請全部做完并記錄下解題思路;
39.C++語言和C++的集成開發(fā)環(huán)境要同時(shí)學(xué)習(xí)和掌握;
40.既然決定了學(xué)C++,就請堅(jiān)持學(xué)下去,因?yàn)閷W(xué)習(xí)程序設(shè)計(jì)語言的目的是掌握程序設(shè)計(jì)技術(shù),而程序設(shè)計(jì)技術(shù)是跨語言的;
41.就讓C++語言的各種平臺和開發(fā)環(huán)境去激烈的競爭吧,我們要以學(xué)習(xí)C++語言本身為主;
42.當(dāng)你寫C++程序?qū)懙揭话雲(yún)s發(fā)現(xiàn)自己用的方法很拙劣時(shí),請不要馬上停手;請盡快將余下的部分粗略的完成以保證這個(gè)設(shè)計(jì)的完整性,然后分析自己的錯(cuò)誤并重新設(shè)計(jì)和編寫(參見43);
43.別心急,設(shè)計(jì)C++的class確實(shí)不容易;自己程序中的class和自己的class設(shè)計(jì)水平是在不斷的編程實(shí)踐中完善和發(fā)展的;
44.決不要因?yàn)槌绦颉昂苄 本筒蛔裱承┠悴皇炀毜囊?guī)則——好習(xí)慣是培養(yǎng)出來的,而不是一次記住的;
45.每學(xué)到一個(gè)C++難點(diǎn)的時(shí)候,嘗試著對別人講解這個(gè)知識點(diǎn)并讓他理解——你能講清楚才說明你真的理解了;
46.記錄下在和別人交流時(shí)發(fā)現(xiàn)的自己忽視或不理解的知識點(diǎn);
47.請不斷的對自己寫的程序提出更高的要求,哪怕你的程序版本號會變成Version 100.XX;
48.保存好你寫過的所有的程序——那是你最好的積累之一;
49.請不要做浮躁的人;
50.請熱愛C++!
第四部分:
C++頭文件一覽 C、傳統(tǒng) C++
#include <assert.h> 設(shè)定插入點(diǎn)#include <ctype.h> 字符處理#include <errno.h> 定義錯(cuò)誤碼#include <float.h> 浮點(diǎn)數(shù)處理#include <fstream.h> 文件輸入/輸出#include <iomanip.h> 參數(shù)化輸入/輸出#include <iostream.h> 數(shù)據(jù)流輸入/輸出#include <limits.h> 定義各種數(shù)據(jù)類型最值常量#include <locale.h> 定義本地化函數(shù)#include <math.h> 定義數(shù)學(xué)函數(shù)#include <stdio.h> 定義輸入/輸出函數(shù)#include <stdlib.h> 定義雜項(xiàng)函數(shù)及內(nèi)存分配函數(shù)#include <string.h> 字符串處理#include <strstrea.h> 基于數(shù)組的輸入/輸出#include <time.h> 定義關(guān)于時(shí)間的函數(shù)#include <wchar.h> 寬字符處理及輸入/輸出#include <wctype.h> 寬字符分類
標(biāo)準(zhǔn) C++
#include <algorithm> 通用算法#include <bitset> 位集容器#include <cctype>#include <cerrno>#include <clocale>#include <cmath>#include <complex> 復(fù)數(shù)類#include <cstdio>#include <cstdlib>#include <cstring>#include <ctime>#include <deque> 雙端隊(duì)列容器#include <exception> 異常處理類#include <fstream>#include <functional> 定義運(yùn)算函數(shù)(代替運(yùn)算符)#include <limits>#include <list> 線性列表容器#include <map> 映射容器#include <iomanip>#include <ios> 基本輸入/輸出支持#include <iosfwd> 輸入/輸出系統(tǒng)使用的前置聲明#include <iostream>#include <istream> 基本輸入流#include <ostream> 基本輸出流#include <queue> 隊(duì)列容器#include <set> 集合容器#include <sstream> 基于字符串的流#include <stack> 堆棧容器 #include <stdexcept> 標(biāo)準(zhǔn)異常類#include <streambuf> 底層輸入/輸出支持#include <string> 字符串類#include <utility> 通用模板類#include <vector> 動(dòng)態(tài)數(shù)組容器#include <cwchar>#include <cwctype>
C99 增加
#include <complex.h> 復(fù)數(shù)處理#include <fenv.h> 浮點(diǎn)環(huán)境#include <inttypes.h> 整數(shù)格式轉(zhuǎn)換#include <stdbool.h> 布爾環(huán)境#include <stdint.h> 整型環(huán)境#include <tgmath.h> 通用類型數(shù)學(xué)宏新聞熱點(diǎn)
疑難解答
圖片精選