1. 程式人生 > >C++中STL用法總結【轉】

C++中STL用法總結【轉】

(轉自:https://blog.csdn.net/piaoxuezhong/article/details/54348787?utm_source=blogxgwz8

1.1 什麼是STL?

STL(Standard Template Library),即標準模板庫,是一個具有工業強度的,高效的C++程式庫。它被容納於C++標準程式庫(C++ Standard Library)中,是ANSI/ISO C++標準中最新的也是極具革命性的一部分。該庫包含了諸多在電腦科學領域裡所常用的基本資料結構和基本演算法。為廣大C++程式設計師們提供了一個可擴充套件的應用框架,高度體現了軟體的可複用性。
STL的一個重要特點是資料結構和演算法的分離。

儘管這是個簡單的概念,但這種分離確實使得STL變得非常通用。例如,由於STL的sort()函式是完全通用的,你可以用它來操作幾乎任何資料集合,包括連結串列,容器和陣列;
STL另一個重要特性是它不是面向物件的。為了具有足夠通用性,STL主要依賴於模板而不是封裝,繼承和虛擬函式(多型性)——OOP的三個要素。你在STL中找不到任何明顯的類繼承關係。這好像是一種倒退,但這正好是使得STL的元件具有廣泛通用性的底層特徵。另外,由於STL是基於模板,行內函數的使用使得生成的程式碼短小高效;
從邏輯層次來看,在STL中體現了泛型化程式設計的思想,引入了諸多新的名詞,比如像需求(requirements),概念(concept),模型(model),容器(container),演算法(algorithmn),迭代子(iterator)等。與OOP(object-oriented programming)中的多型(polymorphism)一樣,泛型也是一種軟體的複用技術;從實現層次看,整個STL是以一種型別引數化的方式實現的,這種方式基於一個在早先C++標準中沒有出現的語言特性--模板(template)。


1.2 STL內容介紹

STL中六大元件:
1)容器(Container),是一種資料結構,如list,vector,和deques ,以模板類的方法提供。為了訪問容器中的資料,可以使用由容器類輸出的迭代器;
2)迭代器(Iterator),提供了訪問容器中物件的方法。例如,可以使用一對迭代器指定list或vector中的一定範圍的物件。迭代器就如同一個指標。事實上,C++的指標也是一種迭代器。但是,迭代器也可以是那些定義了operator*()以及其他類似於指標的操作符地方法的類物件;
3)演算法(Algorithm),是用來操作容器中的資料的模板函式。例如,STL用sort()來對一個vector中的資料進行排序,用find()來搜尋一個list中的物件,函式本身與他們操作的資料的結構和型別無關,因此他們可以在從簡單陣列到高度複雜容器的任何資料結構上使用;
4)仿函式

(Function object)
5)迭代介面卡(Adaptor)
6)空間配製器(allocator)
下面我將依次介紹STL的這三個主要元件。


1.2.1 容器

STL中的容器有佇列容器和關聯容器,容器介面卡(congtainer adapters:stack,queue,priority queue),位集(bit_set),串包(string_package)等等。
(1)序列式容器(Sequence containers),每個元素都有固定位置--取決於插入時機和地點,和元素值無關,vector、deque、list;
Vectors:將元素置於一個動態陣列中加以管理,可以隨機存取元素(用索引直接存取),陣列尾部新增或移除元素非常快速。但是在中部或頭部安插元素比較費時;
Deques:是“double-ended queue”的縮寫,可以隨機存取元素(用索引直接存取),陣列頭部和尾部新增或移除元素都非常快速。但是在中部或頭部安插元素比較費時;
Lists:雙向連結串列,不提供隨機存取(按順序走到需存取的元素,O(n)),在任何位置上執行插入或刪除動作都非常迅速,內部只需調整一下指標;
(2)關聯式容器(Associated containers),元素位置取決於特定的排序準則,和插入順序無關,set、multiset、map、multimap;
Sets/Multisets:內部的元素依據其值自動排序,Set內的相同數值的元素只能出現一次,Multisets內可包含多個數值相同的元素,內部由二叉樹實現,便於查詢;
Maps/Multimaps:Map的元素是成對的鍵值/實值,內部的元素依據其值自動排序,Map內的相同數值的元素只能出現一次,Multimaps內可包含多個數值相同的元素,內部由二叉樹實現,便於查詢;
容器類自動申請和釋放記憶體,無需new和delete操作。vector基於模板實現,需包含標頭檔案vector。

//1.定義和初始化
    vector<int> vec1;    //預設初始化,vec1為空
    vector<int> vec2(vec1);  //使用vec1初始化vec2
    vector<int> vec3(vec1.begin(),vec1.end());//使用vec1初始化vec2
    vector<int> vec4(10);    //10個值為的元素
    vector<int> vec5(10,4);  //10個值為的元素
//2.常用操作方法
    vec1.push_back(100);            //新增元素
    int size = vec1.size();         //元素個數
    bool isEmpty = vec1.empty();    //判斷是否為空
    cout<<vec1[0]<<endl;        //取得第一個元素
    vec1.insert(vec1.end(),5,3);    //從vec1.back位置插入個值為的元素
    vec1.pop_back();              //刪除末尾元素
    vec1.erase(vec1.begin(),vec1.end());//刪除之間的元素,其他元素前移
    cout<<(vec1==vec2)?true:false;  //判斷是否相等==、!=、>=、<=...
    vector<int>::iterator iter = vec1.begin();    //獲取迭代器首地址
    vec1.clear();                 //清空元素
//3.遍歷
    //下標法
    int length = vec1.size();
    for(int i=0;i<length;i++)
    {
       cout<<vec1[i];
    }
    cout<<endl<<endl;
    //迭代器法
    vector<int>::const_iterator iterator = vec1.begin();
    for(;iterator != vec1.end();iterator++)
    {
       cout<<*iterator;
    }

1.2.2.STL迭代器

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

迭代器的作用:能夠讓迭代器與演算法不干擾的相互發展,最後又能無間隙的粘合起來,過載了*,++,==,!=,=運算子。用以操作複雜的資料結構,容器提供迭代器,演算法使用迭代器;常見的一些迭代器型別:iterator、const_iterator、reverse_iterator和const_reverse_iterator,例項如下:
 


#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int> v;
    v.push_back(3);  //陣列尾部插入3
    v.push_back(2);
    v.push_back(1);
    v.push_back(0);
    cout << " 下標 " << v[3] << endl;
    cout << " 迭代器 " << endl;
    for(vector<int>::iterator i = v.begin();i!= v.end();++i)
    {
        cout << *i << " ";
    }
    cout << endl;
    //在第一個元素之前插入111  insert begin+n是在第n個元素之前插入
    v.insert(v.begin(),111);
    //在最後一個元素之後插入222 insert end + n 是在n個元素之後插入
    v.insert(v.end(),222);
    for(vector<int>::iterator i = v.begin();i!= v.end();++i)
    {
        cout << *i << " ";
    }
    cout << endl;
 
    vector<int> arr(10);
    for(int i = 0; i < 10; i++)
    {
        arr[i] = i;
    }
    for(vector<int>::iterator i = arr.begin();i!= arr.end();++i)
    {
        cout << *i << " ";
    }
    cout << endl;
    //刪除 同insert
    arr.erase(arr.begin());
    for(vector<int>::iterator i = arr.begin();i!= arr.end();++i)
     {
        cout << *i << " " ;
     }
    cout << endl ;
    arr.erase(arr.begin(),arr.begin()+5);
    for(vector<int>::iterator i = arr.begin();i!= arr.end();++i)
    {
        cout << *i << " " ;
    }
    cout << endl ;
    return 0 ;
 }

執行結果:


例項2:陣列轉置 (<algorithm> reverse)
     reverse(v.begin(),v.end())

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
    vector<int> v;
    for(int i = 0; i < 10; ++i)
    {
        v.push_back(i);
    }
    for(vector<int>::iterator it = v.begin(); it != v.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;
    reverse(v.begin(),v.end());
    for(vector<int>::iterator it = v.begin(); it != v.end(); ++it)
    {
        cout << *it << " ";
    }
    cout << endl;
    return 0;
}

執行結果:

 

1.2.3、演算法

 

函式庫對資料型別的選擇對其可重用性起著至關重要的作用。舉例來說,一個求方根的函式,在使用浮點數作為其引數型別的情況下的可重用性肯定比使用整型作為它的引數類性要高。而C++通過模板的機制允許推遲對某些型別的選擇,直到真正想使用模板或者說對模板進行特化的時候,STL就利用了這一點提供了相當多的有用演算法。它是在一個有效的框架中完成這些演算法的——你可以將所有的型別劃分為少數的幾類,然後就可以在模版的引數中使用一種型別替換掉同一種類中的其他型別。


STL提供了大約100個實現演算法的模版函式,比如演算法for_each將為指定序列中的每一個元素呼叫指定的函式,stable_sort以你所指定的規則對序列進行穩定性排序等等。只要我們熟悉了STL之後,許多程式碼可以被大大的化簡,只需要通過呼叫一兩個演算法模板,就可以完成所需要的功能並大大地提升效率。


演算法部分主要由標頭檔案<algorithm>,<numeric>和<functional>組成。


<algorithm>是所有STL標頭檔案中最大的一個(儘管它很好理解),它是由一大堆模版函式組成的,可以認為每個函式在很大程度上都是獨立的,其中常用到的功能範圍涉及到比較、交換、查詢、遍歷操作、複製、修改、移除、反轉、排序、合併等等。
<numeric>體積很小,只包括幾個在序列上面進行簡單數學運算的模板函式,包括加法和乘法在序列上的一些操作。
<functional>中則定義了一些模板類,用以宣告函式物件。


STL中演算法大致分為四類:
1)非可變序列演算法:指不直接修改其所操作的容器內容的演算法。
2)可變序列演算法:指可以修改它們所操作的容器內容的演算法。
3)排序演算法:對序列進行排序和合並的演算法、搜尋演算法以及有序序列上的集合操作。
4)數值演算法:對容器內容進行數值計算。
以下對所有演算法進行細緻分類並標明功能:


<一>查詢演算法(13個):判斷容器中是否包含某個值
adjacent_find: 在iterator對標識元素範圍內,查詢一對相鄰重複元素,找到則返回指向這對元素的第一個元素的ForwardIterator。否則返回last。過載版本使用輸入的二元操作符代替相等的判斷。
binary_search: 在有序序列中查詢value,找到返回true。過載的版本實用指定的比較函式物件或函式指標來判斷相等。
count: 利用等於操作符,把標誌範圍內的元素與輸入值比較,返回相等元素個數。
count_if: 利用輸入的操作符,對標誌範圍內的元素進行操作,返回結果為true的個數。
equal_range: 功能類似equal,返回一對iterator,第一個表示lower_bound,第二個表示upper_bound。
find: 利用底層元素的等於操作符,對指定範圍內的元素與輸入值進行比較。當匹配時,結束搜尋,返回該元素的一個InputIterator。
find_end: 在指定範圍內查詢"由輸入的另外一對iterator標誌的第二個序列"的最後一次出現。找到則返回最後一對的第一個ForwardIterator,否則返回輸入的"另外一對"的第一個ForwardIterator。過載版本使用使用者輸入的操作符代替等於操作。
find_first_of: 在指定範圍內查詢"由輸入的另外一對iterator標誌的第二個序列"中任意一個元素的第一次出現。過載版本中使用了使用者自定義操作符。
find_if: 使用輸入的函式代替等於操作符執行find。
lower_bound: 返回一個ForwardIterator,指向在有序序列範圍內的可以插入指定值而不破壞容器順序的第一個位置。過載函式使用自定義比較操作。
upper_bound: 返回一個ForwardIterator,指向在有序序列範圍內插入value而不破壞容器順序的最後一個位置,該位置標誌一個大於value的值。過載函式使用自定義比較操作。
search: 給出兩個範圍,返回一個ForwardIterator,查詢成功指向第一個範圍內第一次出現子序列(第二個範圍)的位置,查詢失敗指向last1。過載版本使用自定義的比較操作。
search_n: 在指定範圍內查詢val出現n次的子序列。過載版本使用自定義的比較操作。


<二>排序和通用演算法(14個):提供元素排序策略
inplace_merge: 合併兩個有序序列,結果序列覆蓋兩端範圍。過載版本使用輸入的操作進行排序。
merge: 合併兩個有序序列,存放到另一個序列。過載版本使用自定義的比較。
nth_element: 將範圍內的序列重新排序,使所有小於第n個元素的元素都出現在它前面,而大於它的都出現在後面。過載版本使用自定義的比較操作。
partial_sort: 對序列做部分排序,被排序元素個數正好可以被放到範圍內。過載版本使用自定義的比較操作。
partial_sort_copy: 與partial_sort類似,不過將經過排序的序列複製到另一個容器。
partition: 對指定範圍內元素重新排序,使用輸入的函式,把結果為true的元素放在結果為false的元素之前。
random_shuffle: 對指定範圍內的元素隨機調整次序。過載版本輸入一個隨機數產生操作。
reverse: 將指定範圍內元素重新反序排序。
reverse_copy: 與reverse類似,不過將結果寫入另一個容器。
rotate: 將指定範圍內元素移到容器末尾,由middle指向的元素成為容器第一個元素。
rotate_copy: 與rotate類似,不過將結果寫入另一個容器。
sort: 以升序重新排列指定範圍內的元素。過載版本使用自定義的比較操作。
stable_sort: 與sort類似,不過保留相等元素之間的順序關係。
stable_partition: 與partition類似,不過不保證保留容器中的相對順序。


<三>刪除和替換演算法(15個)
copy: 複製序列
copy_backward: 與copy相同,不過元素是以相反順序被拷貝。
iter_swap: 交換兩個ForwardIterator的值。
remove: 刪除指定範圍內所有等於指定元素的元素。注意,該函式不是真正刪除函式。內建函式不適合使用remove和remove_if函式。
remove_copy: 將所有不匹配元素複製到一個制定容器,返回OutputIterator指向被拷貝的末元素的下一個位置。
remove_if: 刪除指定範圍內輸入操作結果為true的所有元素。
remove_copy_if: 將所有不匹配元素拷貝到一個指定容器。
replace: 將指定範圍內所有等於vold的元素都用vnew代替。
replace_copy: 與replace類似,不過將結果寫入另一個容器。
replace_if: 將指定範圍內所有操作結果為true的元素用新值代替。
replace_copy_if: 與replace_if,不過將結果寫入另一個容器。
swap: 交換儲存在兩個物件中的值。
swap_range: 將指定範圍內的元素與另一個序列元素值進行交換。
unique: 清除序列中重複元素,和remove類似,它也不能真正刪除元素。過載版本使用自定義比較操作。
unique_copy: 與unique類似,不過把結果輸出到另一個容器。


<四>排列組合演算法(2個):提供計算給定集合按一定順序的所有可能排列組合
next_permutation: 取出當前範圍內的排列,並重新排序為下一個排列。過載版本使用自定義的比較操作。
prev_permutation: 取出指定範圍內的序列並將它重新排序為上一個序列。如果不存在上一個序列則返回false。過載版本使用自定義的比較操作。


<五>算術演算法(4個)
accumulate: iterator對標識的序列段元素之和,加到一個由val指定的初始值上。過載版本不再做加法,而是傳進來的二元操作符被應用到元素上。
partial_sum: 建立一個新序列,其中每個元素值代表指定範圍內該位置前所有元素之和。過載版本使用自定義操作代替加法。
inner_product: 對兩個序列做內積(對應元素相乘,再求和)並將內積加到一個輸入的初始值上。過載版本使用使用者定義的操作。
adjacent_difference: 建立一個新序列,新序列中每個新值代表當前元素與上一個元素的差。過載版本用指定二元操作計算相鄰元素的差。


<六>生成和異變演算法(6個)
fill: 將輸入值賦給標誌範圍內的所有元素。
fill_n: 將輸入值賦給first到first+n範圍內的所有元素。
for_each: 用指定函式依次對指定範圍內所有元素進行迭代訪問,返回所指定的函式型別。該函式不得修改序列中的元素。
generate: 連續呼叫輸入的函式來填充指定的範圍。
generate_n: 與generate函式類似,填充從指定iterator開始的n個元素。
transform: 將輸入的操作作用與指定範圍內的每個元素,併產生一個新的序列。過載版本將操作作用在一對元素上,另外一個元素來自輸入的另外一個序列。結果輸出到指定容器。


<七>關係演算法(8個)
equal: 如果兩個序列在標誌範圍內元素都相等,返回true。過載版本使用輸入的操作符代替預設的等於操作符。
includes: 判斷第一個指定範圍內的所有元素是否都被第二個範圍包含,使用底層元素的<操作符,成功返回true。過載版本使用使用者輸入的函式。
lexicographical_compare: 比較兩個序列。過載版本使用使用者自定義比較操作。
max: 返回兩個元素中較大一個。過載版本使用自定義比較操作。
max_element: 返回一個ForwardIterator,指出序列中最大的元素。過載版本使用自定義比較操作。
min: 返回兩個元素中較小一個。過載版本使用自定義比較操作。
min_element: 返回一個ForwardIterator,指出序列中最小的元素。過載版本使用自定義比較操作。
mismatch: 並行比較兩個序列,指出第一個不匹配的位置,返回一對iterator,標誌第一個不匹配元素位置。如果都匹配,返回每個容器的last。過載版本使用自定義的比較操作。


<八>集合演算法(4個)
set_union: 構造一個有序序列,包含兩個序列中所有的不重複元素。過載版本使用自定義的比較操作。
set_intersection: 構造一個有序序列,其中元素在兩個序列中都存在。過載版本使用自定義的比較操作。
set_difference: 構造一個有序序列,該序列僅保留第一個序列中存在的而第二個中不存在的元素。過載版本使用自定義的比較操作。
set_symmetric_difference: 構造一個有序序列,該序列取兩個序列的對稱差集(並集-交集)。


<九>堆演算法(4個)
make_heap: 把指定範圍內的元素生成一個堆。過載版本使用自定義比較操作。
pop_heap: 並不真正把最大元素從堆中彈出,而是重新排序堆。它把first和last-1交換,然後重新生成一個堆。可使用容器的back來訪問被"彈出"的元素或者使用pop_back進行真正的刪除。過載版本使用自定義的比較操作。
push_heap: 假設first到last-1是一個有效堆,要被加入到堆的元素存放在位置last-1,重新生成堆。在指向該函式前,必須先把元素插入容器後。過載版本使用指定的比較操作。
sort_heap: 對指定範圍內的序列重新排序,它假設該序列是個有序堆。過載版本使用自定義比較操作。
...
參考:
http://www.cnblogs.com/giszhang/archive/2010/02/02/1661844.html
http://blog.csdn.net/conanswp/article/details/23297441
http://www.cnblogs.com/biyeymyhjob/archive/2012/07/22/2603525.html
http://blog.chinaunix.net/uid-24219701-id-2181266.html