C++容器和泛型

一、順序容器

1,標準庫定義了3種類型的順序容器:vector、list和deque。它們的差別主要在於訪問元素的方式,以及添加或刪除元素相關操作運算代價。標準庫還提供了三種容器適配器:stack、queue和priority_queue。

2,將一個容器複製給另一個容器時,類型必須匹配,包括容器類型和元素類型。

vector ivec; vector dvec(ivec); //errorlist ilist(ivec); // error

3,可以用一對指針或一對迭代器,把它們之間的值複製給容器,可以允許類型不一致。

vector svec; list slist(svec.begin(),svec.end()); vector::iterator mid = svec.begin() + svec.size() / 2; deque front(svec.begin(),mid); // 不包括 mid // 用指針初始化char word[] = {“monday”,“tuesday”,“wesday”}; size_t words_size = sizeof(word) / sizeof(char*); list words2(word, word + words_size);

4,注意除了引用外,所有內置或複合類型都可以做容器的元素類型。引用不支持一般意義的賦值操作。除輸入輸出標準庫類型(以及auto_ptr)外,所有其他標準庫類型都是有效的容器元素類型。

5,list容器的迭代器不支持算術運算,也不支持關係運算。因爲list裏的元素,沒有序號或位置這個概念。

6,所有相同類型的容器都支持關係操作符來實現兩個容器的比較:

1)如果兩個容器具有相同的長度而且所有元素都相等,那麼兩個兩個容器相等;否則,就不相等。

2)如果兩個容器的長度不相同,但較短的容器中所有元素都等於較長容器中對應的元素,則稱較短的容器小於另一容器。

3)如果兩個容器都不是對方的初始子序列,則它們的比較結果取決於所比較的第一個不相等的元素。

如果容器內的元素不支持比較大小,則容器就不能比較大小。

7,獲得容器元素的引用,有兩種方法:1)front與back成員函數;2)迭代器解引用。

list ilist; if (!ilist.empty()) { list::reference val = ilist.front(); list::reference val1 = *ilist.begin(); list::reference last = ilist.back(); list::reference last1 = *–ilist.end(); }

注意取引用時,一定要保證ilist非空。

8,在使用erase刪除容器內兩個迭代器之間的元素時,erase(elem1,elem2),這裏刪除的元素不包括elem2。

9,容器的賦值,順序容器有幾下幾種賦值操作:

1)c1=c2:刪除c1的所有元素,然後將c2的元素複製給c1,c1和c2的類型(容器類型與元素類型)必須相同。

2)c1.swap(c2):顧名思義,交換c1與c2的值,實際上這個操作,只是交換了彼此的地址。交換後c1批向了原來c2的指針內容。

3)c.assign(b,e):重新設置c的元素,將迭代器b與e之間的所有元素複製到c中,當然b與e不能是c的的迭代器。

4)c.assign(n,t):將容器c重新設置爲存儲n個值爲t的元素。

注意assign操作允許發生類型轉換。可以將char*元素assign給存儲string的容器。swap是速度最快的,沒有刪除元素的成本。

10,一般意義下vector的元素是按順序存儲的,這就造成了,如果插入元素,則庫將進行重新內存分配,並涉及到的舊vector的銷燬。而實際中vector容器預留了這些額外的存儲區用於存放新添加的元素。因此在實際上,比起list與deqeue容器,vector的增長效率通常會更高。

11,vector容器實際空間可能會比元素所佔的空間更大,capacity成員函數用於返回容器實際的容量大小,一般比size要大。如果一直往vector內插入元素,則直到size==capacity之間,vector都不用重新進行內存分配。但如果再往裏插入元素時,將又會重新分配,capacity又會比size大。

二、 關聯容器

1,pair類型:

pair<string, string> name(“ronny”, “young”); // 定義並初始化name = make_pair(“ronny”, “young”); string fullName = name.first + name.second;

2,關聯容器

1)關聯容器map實際上是裝有n個pair類型的集合。map定義了三個類型別名,key_type、mapped_type、value_type分別表示鍵的類型、鍵所關聯的值的類型和map裏pair類型。

2)當使用下標訪問map的值時,如果下標不存在,則導致在map中新添一個新的元素,它的鍵即爲該下標值。

3)map的迭代器指向的是pair類型,所以當對迭代器解引用時,得到的是一個pair類型。這與下標得到的類型不同。

4)統計單詞出現次數的例子:

map<string, int> word_cnt; string word; while (cin >> word) { ++word_cnt[word]; }

5)利用insert返回的類型來重寫上面的程序,insert返回了一個pair類型,它的first成員爲一個迭代器,而second成員爲一個bool變量,表明該元素是否被插入。

map<string, int> word_cnt; string word; while (cin >> word) { pair<map<string, int>::iterator, bool> ret = word_cnt.insert(make_pair(word, 1)); if (!ret.second) ++(ret.first)->second; }

6)set容器是一個集合,它存儲了鍵,且惟一不能修改。set的操作與map基本一致,只是沒有mapped_type,而且vale_type就是key_type。在使用insert時,返回的也是pair類型的值。set不提供下標操作,只能使用find來查找元素是否存在,並且返回一個迭代器,如果不存在,則返回指向最後一個元素下一個的迭代器(end)。如果簡單的判斷某個鍵是否存在,則可以直接使用cout函數,它返回1或0。

7)multimap與multiset容器允許一個鍵值對應多個實例,實際上一個鍵值的多個實例是按順序存儲在一起的。它們的find的操作返回鍵值第一個實例的迭代器,cout返回鍵值有多少個實例。另外lower_bound與upper_bound分別用於返回所查找鍵值的第一個實例我迭代器與最後一個實例迭代器的下一位。

multimap<string, string> books; typedef multimap<string, string>::iterator authors_it; string search_item = “matin”; authors_it beg = books.lower_bound(search_item); authors_it end = books.upper_bound(search_item); while (beg != end) { cout << (beg++)->second << endl; }

更加方便的是equal_range函數,它返回了一個迭代器的pair對象,其實正好放着lower_bound和upper_bound

三、 泛型算法

1,泛型算法大部分在algorithm頭文件中,而還有一些算術算法,它們在頭文件numeric中。

2,int sum=accumulate(vec.begin,vec.end(),42)。accumulate返回一對迭代器之間元素和。注意第三個參數是很重要的,一方面它指定了sum的類型,使該類型可以進行加法運算;另一方面限制了容器的類型必須與第三個參數類型保持一致或可以轉換。得到的sum爲第三個參數的類型。

3,find_first_of用於查找第二段範圍裏的對象在第一段範圍裏出現的第一個位置。

while (it=find_first_of(it,roster1.end,roster2.begin(),roster2.end()) !=roster1.end())

上面代碼用來循環查找,roster2中的元素在roster1中出現的位置。find_first_of的兩個範圍內的對象,並不要求容器類型一致,只需要容器內的元素可以進行比較即可。

4,寫入算法:

fill(vec.begin(),vec.end(),0):將一對迭代器範圍內的值設置爲第三個參數的值。

fill_n(vec.begin(),10,0):如果vec內元素小於10個時,這段代碼將會出現問題。用插入迭代器可以解決fill_n(back_inserter(vec),10,0);

copy(ilst.begin(),ilist.end(),back_inserter(ivec))會將ilist內的元素複製到ivec中。

replace(ilst.begin(),ilst.end(),0,42):將ilst中所有值爲0的元素全部值設爲42.

replace_copy(ilst.begin(),ilst.end(),back_inserter(ivec),0,42):ilst沒有發生變化,ivec將儲存ilst的一份副本,其實值爲0的都變爲了42.

5,去重複、排序算法

char * arStr[] = { “the”, “quick”, “red”, “fox”, “jumps”, “over”, “the”, “slow”, “red”, “turtle” }; vector sVec(arStr, arStr + 10); sort(sVec.begin(), sVec.end()); vector::iterator end_uniuqe = unique(sVec.begin(), sVec.end()); sVec.erase(end_uniuqe,sVec.end()); stable_sort(sVec.begin(), sVec.end(), isShorter); vector::size_type len = count_if(sVec.begin(), sVec.end(), LongerThan6); bool isShorter(const string& s1, const string& s2) { return s1.size() < s2.size(); } bool LongerThan6(const string& s) { return s.size() >= 6; }

上面程序中,unique是一個去重複的函數,返回已經沒有重複的序列最後一位下一個元素位置。

stable_sort可以保留重複元素開始的相對位置

7,插入迭代器:

front_inserter:調用push_front插入

back_inserter:調用push_back插入

inserter:調用insert插入

list<int

::iterator it = find(ilst.begin(),ilst.end(),42); // 先將ivec的一份拷貝中值爲100的元素換爲0,然後將其插入到ilst的迭代器it的前面 replace_copy(ivec.begin(),ivec.end(),inserter(ilst,it),100,0);

上面三種操作一般都與copy或replace_copy函數一起用,作爲其一個實參。

list lst1, lst2, lst3; for (list::size_type i = 0; i != 5; i++) { lst1.push_back(i); } copy(lst1.begin(), lst1.end(), inserter(lst2, lst2.begin())); copy(lst1.begin(), lst1.end(), front_inserter(lst3));

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章