天天看點

全網最全面的STL總結與常見面試題,值得收藏(一)

1 STL概述

為了建立資料結構和算法的一套标準,并且降低他們之間的耦合關系,以提升各自的獨立性、彈性、互動操作性(互相合作性,interoperability),誕生了STL。

程式員必備資源,值得收藏!點選下載下傳

STL提供了六大元件,彼此之間可以組合套用,這六大元件分别是:容器、算法、疊代器、仿函數、擴充卡(配接器)、空間配置器。

容器:各種資料結構,如vector、list、deque、set、map等,用來存放資料,從實作角度來看,STL容器是一種class template。

算法:各種常用的算法,如sort、find、copy、for_each。從實作的角度來看,STL算法是一種function tempalte.

疊代器:扮演了容器與算法之間的膠合劑,共有五種類型,從實作角度來看,疊代器是一種将operator* , operator-> , operator++,operator–等指針相關操作予以重載的class template. 所有STL容器都附帶有自己專屬的疊代器,隻有容器的設計者才知道如何周遊自己的元素。原生指針(native pointer)也是一種疊代器。

仿函數:行為類似函數,可作為算法的某種政策。從實作角度來看,仿函數是一種重載了operator()的class 或者class template

擴充卡:一種用來修飾容器或者仿函數或疊代器接口的東西。

空間配置器:負責空間的配置與管理。從實作角度看,配置器是一個實作了動态空間配置、空間管理、空間釋放的class tempalte.

STL六大元件的互動關系,容器通過空間配置器取得資料存儲空間,算法通過疊代器存儲容器中的内容,仿函數可以協助算法完成不同的政策的變化,擴充卡可以修飾仿函數。

2 STL的優點:

STL 是 C++的一部分,是以不用額外安裝什麼,它被内建在你的編譯器之内。

STL 的一個重要特性是将資料和操作分離。資料由容器類别加以管理,操作則由可定制的算法定義。疊代器在兩者之間充當“粘合劑”,以使算法可以和容器互動運作

程式員可以不用思考 STL 具體的實作過程,隻要能夠熟練使用 STL 就 OK 了。這樣他們就可以把精力放在程式開發的别的方面。

STL 具有高可重用性,高性能,高移植性,跨平台的優點。

高可重用性:STL 中幾乎所有的代碼都采用了模闆類和模版函數的方式實作,這相比于傳統的由函數和類組成的庫來說提供了更好的代碼重用機會。

高性能:如 map 可以高效地從十萬條記錄裡面查找出指定的記錄,因為 map 是采用紅黑樹的變體實作的。

高移植性:如在項目 A 上用 STL 編寫的子產品,可以直接移植到項目 B 上。容器和算法之間通過疊代器進行無縫連接配接。STL 幾乎所有的代碼都采用了模闆類或者模闆函數,這相比傳統的由函數和類組成的庫來說提供了更好的代碼重用機會。

3 容器

STL容器就是将運用最廣泛的一些資料結構實作出來。

常用的資料結構:數組(array) , 連結清單(list), tree(樹),棧(stack), 隊列(queue), 集合(set),映射表(map), 根據資料在容器中的排列特性,這些資料分為序列式容器和關聯式容器兩種。

序列式容器強調值的排序,序列式容器中的每個元素均有固定的位置,除非用删除或插入的操作改變這個位置。Vector容器、Deque容器、List容器等。

關聯式容器是非線性的樹結構,更準确的說是二叉樹結構。各元素之間沒有嚴格的實體上的順序關系,也就是說元素在容器中并沒有儲存元素置入容器時的邏輯順序。關聯式容器另一個顯著特點是:在值中選擇一個值作為關鍵字key,這個關鍵字對值起到索引的作用,友善查找。Set/multiset容器 Map/multimap容器

容器 底層資料結構 時間複雜度 有無序 可不可重複

array 數組 随機讀改 O(1) 無序 可重複

vector 數組 随機讀改、尾部插入、尾部删除 O(1)頭部插入、頭部删除 O(n) 無序 可重複

deque 雙端隊列 頭尾插入、頭尾删除 O(1) 無序 可重複

forward_list 單向連結清單 插入、删除 O(1) 無序 可重複

list 雙向連結清單 插入、删除 O(1) 無序 可重複

stack deque / list 頂部插入、頂部删除 O(1) 無序 可重複

queue deque / list 尾部插入、頭部删除 O(1) 無序 可重複

priority_queue vector /max-heap 插入、删除 O(log2n) 有序 可重複

set 紅黑樹 插入、删除、查找 O(log2n) 有序 不可重複

multiset 紅黑樹 插入、删除、查找 O(log2n) 有序 可重複

map 紅黑樹 插入、删除、查找 O(log2n) 有序 不可重複

multimap 紅黑樹 插入、删除、查找 O(log2n) 有序 可重複

unordered_set 哈希表 插入、删除、查找 O(1) 最差 O(n) 無序 不可重複

unordered_multiset 哈希表 插入、删除、查找 O(1) 最差 O(n) 無序 可重複

unordered_map 哈希表 插入、删除、查找 O(1) 最差 O(n) 無序 不可重複

unordered_multimap 哈希表 插入、删除、查找 O(1) 最差 O(n) 無序 可重複

1 array

array 是固定大小的順序容器,它們儲存了一個以嚴格的線性順序排列的特定數量的元素。

方法 說明

begin 傳回指向數組容器中第一個元素的疊代器

end 傳回指向數組容器中最後一個元素之後的理論元素的疊代器

rbegin 傳回指向數組容器中最後一個元素的反向疊代器

rend 傳回一個反向疊代器,指向數組中第一個元素之前的理論元素

cbegin 傳回指向數組容器中第一個元素的常量疊代器(const_iterator)

cend 傳回指向數組容器中最後一個元素之後的理論元素的常量疊代器(const_iterator)

crbegin 傳回指向數組容器中最後一個元素的常量反向疊代器(const_reverse_iterator)

crend 傳回指向數組中第一個元素之前的理論元素的常量反向疊代器(const_reverse_iterator)

size 傳回數組容器中元素的數量

max_size 傳回數組容器可容納的最大元素數

empty 傳回一個布爾值,訓示數組容器是否為空

operator[] 傳回容器中第 n(參數)個位置的元素的引用

at 傳回容器中第 n(參數)個位置的元素的引用

front 傳回對容器中第一個元素的引用

back 傳回對容器中最後一個元素的引用

data 傳回指向容器中第一個元素的指針

fill 用 val(參數)填充數組所有元素

swap 通過 x(參數)的内容交換數組的内容

get(array) 形如 std::get<0>(myarray);傳入一個數組容器,傳回指定位置元素的引用

relational operators (array) 形如 arrayA > arrayB;依此比較數組每個元素的大小關系

測試代碼

#include<iostream>
#include<array>
using namespace std;
 
int main() 
{
    array<int, 8> myArr = {1,3,4,6,9};//固定大小為8
    cout << "myArr元素序列:";
    for (auto i = 0; i < 8; ++i) 
    {
        cout << myArr[i] << " ";
    }
    cout << endl;
 
    array<int, 8> myArr1 = {2,3,4,7,8,9};//固定大小為8
    cout << "myArr1元素序列:";
    for (auto i = 0; i < 8; ++i) 
    {
        cout << myArr1[i] << " ";
    }
    cout << endl;
 
    myArr.swap(myArr1);   //交換兩個容器的内容
    cout << "交換myArr與myArr1"<< endl;
    cout << endl;
 
    cout << "myArr.at(3) = " << myArr.at(3) << endl;//任意通路
    cout << "myArr[3] = " << myArr[3] << endl;//任意通路
    cout << "myArr.front() = " << myArr.front() << endl;//擷取第一個元素
    cout << "myArr.back() =  " << myArr.back() << endl;//擷取最後一個元素
    cout << "myArr.data() = " << myArr.data() << endl;//擷取第一個元素的指針
    cout << "*myArr.data() = " << *myArr.data() << endl;//擷取第一個元素的指針指向的元素
 
    cout << "正向疊代器周遊容器:";
    for (auto it = myArr.begin(); it != myArr.end(); ++it) 
    {
        cout << *it << " ";
    }
    cout << endl;
    //逆向疊代器測試
    cout << "逆向疊代器周遊容器:";
    for (auto rit = myArr.rbegin(); rit != myArr.rend(); ++rit) 
    {
        cout << *rit << " ";
    }
    cout << endl;
    //正向常疊代器測試
    cout << "正向常疊代器周遊容器:";
    for (auto it = myArr.cbegin(); it != myArr.cend(); ++it) 
    {
        cout << *it << " ";
    }
    cout << endl;
    //逆向常疊代器測試
    cout << "逆向常疊代器周遊容器:";
    for (auto rit = myArr.crbegin(); rit != myArr.crend(); ++rit) 
    {
        cout << *rit << " ";
    }
    cout << endl;
    if(myArr.empty())
        cout << "myArr為空 " << endl;
    else
        cout << "myArr不為空 " << endl;
    cout << "myArr.size() = " << myArr.size() << endl;
    cout << "myArr.max_size() = " << myArr.max_size() << endl;
 
    return 0;
}
 

      

運作結果

全網最全面的STL總結與常見面試題,值得收藏(一)

vector

vector 是表示可以改變大小的數組的序列容器。

vector 構造函數

~vector 析構函數,銷毀容器對象

operator= 将新内容配置設定給容器,替換其目前内容,并相應地修改其大小

begin 傳回指向容器中第一個元素的疊代器

end 傳回指向容器中最後一個元素之後的理論元素的疊代器

rbegin 傳回指向容器中最後一個元素的反向疊代器

rend 傳回一個反向疊代器,指向中第一個元素之前的理論元素

cbegin 傳回指向容器中第一個元素的常量疊代器(const_iterator)

cend 傳回指向容器中最後一個元素之後的理論元素的常量疊代器(const_iterator)

crbegin 傳回指向容器中最後一個元素的常量反向疊代器(const_reverse_iterator)

crend 傳回指向容器中第一個元素之前的理論元素的常量反向疊代器(const_reverse_iterator)

size 傳回容器中元素的數量

max_size 傳回容器可容納的最大元素數

resize 調整容器的大小,使其包含 n(參數)個元素

capacity 傳回目前為 vector 配置設定的存儲空間(容量)的大小

empty 傳回 vector 是否為空

reserve 請求 vector 容量至少足以包含 n(參數)個元素

shrink_to_fit 要求容器減小其 capacity(容量)以适應其 size(元素數量)

assign 将新内容配置設定給 vector,替換其目前内容,并相應地修改其 size

push_back 在容器的最後一個元素之後添加一個新元素

pop_back 删除容器中的最後一個元素,有效地将容器 size 減少一個

insert 通過在指定位置的元素之前插入新元素來擴充該容器,通過插入元素的數量有效地增加容器大小

erase 從 vector 中删除單個元素(position)或一系列元素([first,last)),這有效地減少了被去除的元素的數量,進而破壞了容器的大小

swap 通過 x(參數)的内容交換容器的内容,x 是另一個類型相同、size 可能不同的 vector 對象

clear 從 vector 中删除所有的元素(被銷毀),留下 size 為 0 的容器

emplace 通過在 position(參數)位置處插入新元素 args(參數)來擴充容器

emplace_back 在 vector 的末尾插入一個新的元素,緊跟在目前的最後一個元素之後

get_allocator 傳回與vector關聯的構造器對象的副本

swap(vector) 容器 x(參數)的内容與容器 y(參數)的内容交換。兩個容器對象都必須是相同的類型(相同的模闆參數),盡管大小可能不同

relational operators (vector) 形如 vectorA > vectorB;依此比較每個元素的大小關系

#include <vector>
#include <iostream>
using namespace std;
 
int main()
{
 
    //構造函數,複制構造函數(元素類型要一緻),
    vector<int> vecA;  //建立一個空的的容器
    vector<int> vecB(10,20); //建立一個10個元素,每個元素值為20
    vector<int> vecC(vecB.begin(),vecB.end()); //使用疊代器,可以取部分元素建立一個新的容器
    vector<int> vecD(vecC); //複制構造函數,建立一個完全一樣的容器
 
    //重載=
    vector<int> vecE;
    vecE = vecB;
 
    //vector::begin(),傳回的是疊代器
 
    vector<int> vecF(10); //建立一個有10個元素的容器
    cout << "vecF:";
    for (int i = 0; i < 10; i++)
    {
        vecF[i] = i;
        cout << vecF[i]<< " ";
    }
    cout << endl;
 
    //vector::begin() 傳回疊代器
    vector<int>::iterator Beginit = vecF.begin();
    cout<< "vecF.begin():" << *Beginit << endl; 
 
    //vector::end() 傳回疊代器
    vector<int>::iterator EndIter = vecF.end();
    EndIter--; //向後移一個位置
    cout <<"vecF.end():"<< *EndIter << endl; 
 
    //vector::rbegin() 傳回倒序的第一個元素,相當于最後一個元素
    vector<int>::reverse_iterator ReverBeIter = vecF.rbegin();
    cout << "vecF.rbegin(): "<< *ReverBeIter << endl; 
 
    //vector::rend() 反序的最後一個元素下一個位置,也相當于正序的第一個元素前一個位置
    vector<int>::reverse_iterator ReverEnIter = vecF.rend();
    ReverEnIter--;
    cout << "vecF.rend():"<< *ReverEnIter << endl; 
 
    //vector::size() 傳回元素的個數
    cout << "vecF.size():"<< vecF.size() << endl; 
 
    //vector::max_size()
    cout << "vecF.max_size():"<< vecF.max_size() << endl; 
 
    //vector::resize()
    cout<< "vecF.size():" << vecF.size() << endl; 
    vecF.resize(5);
 
    cout<< "調整vecF大小後重新指派:"; 
    for(int k = 0; k < vecF.size(); k++)
        cout << vecF[k] << "  "; 
    cout << endl;
 
    //vector::capacity()
    cout<< "調整後vecF.size():"<< vecF.size() << endl; 
    cout<< "調整後vecF.capacity():" << vecF.capacity() << endl; 
 
    //vector::empty()
    vecB.resize(0);
    cout<< "vecB.resize(0)後"<< endl; 
 
    cout  << "vecB.size():" << vecB.size() << endl; 
    cout  << "vecB.capacity():" << vecB.capacity() << endl; 
    if(vecB.empty())
        cout << "vecB為空"<< endl; 
    else
        cout << "vecB不為空"<< endl; 
 
    //vector::reserve() //重新配置設定存儲空間大小
    cout<< "vecC.capacity():" << vecC.capacity() << endl; //
 
    vecC.reserve(4);
    cout << "vecC.reserve(4)後vecC.capacity(): "<< vecC.capacity() << endl; //10
    vecC.reserve(14);
    cout << "vecC.reserve(14)後vecC.capacity(): "<< vecC.capacity() << endl; //14
 
    //vector::operator []
    cout << "vecF[0]:"<< vecF[0] << endl; //第一個元素是0
 
    //vector::at()
    try
    {
        cout << "vecF.size = " << vecF.size() << endl; //5
        cout << vecF.at(6) << endl; //抛出異常
    }
    catch(out_of_range)
    {   
        cout << "at()通路越界" << endl;
    }
 
    //vector::front() 傳回第一個元素的值
    cout << "vecF.front():"<< vecF.front() << endl; //0
 
    //vector::back()
    cout << "vecF.back():"<< vecF.back() << endl; //4
 
    //vector::assign()
    cout <<"vecA.size():"<< vecA.size() << endl; //0
    vector<int>::iterator First = vecC.begin();
    vector<int>::iterator End = vecC.end()-2;
    vecA.assign(First,End);
    cout << vecA.size() << endl; //8
    cout << vecA.capacity() << endl; //8
 
    vecA.assign(5,3); //将丢棄原來的所有元素然後重新指派
    cout << vecA.size() << endl; //5
    cout << vecA.capacity() << endl; //8
 
    //vector::push_back()
    cout << *(vecF.end()-1) << endl; //4
    vecF.push_back(20);
    cout << *(vecF.end()-1) << endl; //20
 
    //vector::pop_back()
    cout << *(vecF.end()-1) << endl; //20
    vecF.pop_back();
    cout << *(vecF.end()-1) << endl; //4
 
    //vector::swap()
    cout << "vecF:";
    for (int i = 0; i < vecF.size(); i++)
    {
        vecF[i] = i;
        cout << vecF[i]<< " ";
    }
    cout << endl;
    cout << "vecD:";
    for (int d = 0; d < vecD.size(); d++)
    {
        vecD[d] = d;
        cout << vecD[d]<< " ";
    }
    cout << endl;
 
    vecF.swap(vecD); //交換這兩個容器的内容
    cout <<"vecD與vecF交換後:" <<endl;
    cout << "vecF:";
    for(int f = 0; f < vecF.size(); f++)
        cout << vecF[f] << " ";
    cout << endl;
 
    cout << "vecD:";
    for (int d = 0; d <vecD.size(); d++)
        cout << vecD[d] << " ";
    cout << endl;
    //vector::clear()
    vecF.clear();
    cout << "vecF.clear()後vecF.size():"<< vecF.size() << endl;     //0
    cout << "vecF.clear()後vecF.capacity():"<< vecF.capacity() << endl; //10
 
    return 0;
}

      

繼續閱讀