学了C++不会STL,简直少了左膀右臂
什么是STL :
容器(Container):
是一種數據結構,如list,vector,和deques ,以模板類的方法提供。為了訪問容器中的數據,可以使用由容器類輸出的迭代器;
迭代器(Iterator):
提供了訪問容器中對象的方法。例如,可以使用一對迭代器指定list或vector中的一定范圍的對象。迭代器就如同一個指針。事實上,C++的指針也是一種迭代器。但是,迭代器也可以是那些定了operator*()以及其他類似于指針的操作符地方法的類對象;
算法(Algorithm):
是用來操作容器中的數據的模板函數。例如,STL用sort()來對一個vector中的數據進行排序,用find()來搜索一個list中的對象,函數本身與他們操作的數據的結構和類型無關,因此他們可以在從簡單數組到高度復雜容器的任何數據結構上使用;
仿函數(Functor)
適配器(Adaptor)
分配器(allocator)
仿函數、適配器、與分配器用的比較少,甚至沒用過!在這里不做說明,有興趣可以自己學習一下,那個東西C++軟件工程可能用的比較多。
一、迭代器(Iterator)
背景:指針可以用來遍歷存儲空間連續的數據結構,但是對于存儲空間費連續的,就需要尋找一個行為類似指針的類,來對非數組的數據結構進行遍歷。
定義:迭代器是一種檢查容器內元素并遍歷元素的數據類型。
迭代器提供對一個容器中的對象的訪問方法,并且定義了容器中對象的范圍。
迭代器(Iterator)是指針(pointer)的泛化,它允許程序員用相同的方式處理不同的數據結構(容器)。
(1)迭代器類似于C語言里面的指針類型,它提供了對對象的間接訪問。
(2)指針是C語言中的知識點,迭代器是C++中的知識點。指針較靈活,迭代器功能較豐富。
(3)迭代器提供一個對容器對象或者string對象的訪問方法,并定義了容器范圍。
迭代器和指針的區別:
容器和string有迭代器類型同時擁有返回迭代器的成員。如:容器有成員begin和end,其中begin成員復制返回指向第一個元素的迭代器,而end成員返回指向容器尾元素的下一個位置的迭代器,也就是說end指示的是第一個不合法地址,所以end返回的是尾后迭代器。
容器迭代器的使用
每種容器類型都定義了自己的迭代器類型,如vector:vector< int>:: iterator iter;//定義一個名為iter的變量,數據類型是由vector< int>定義的iterator 類型。簡單說就是容器類定義了自己的iterator類型,用于訪問容器內的元素。每個容器定義了一種名為iterator的類型,這種類型支持迭代器的各種行為。
我么們先講一下各種迭代器的類型,在講容器所用的迭代器類型,就可以明白怎么操作。
常見迭代器類型如下:
| p++ | 后置自增迭代器 |
| ++p | 前置自增迭代器 |
| 輸入迭代器 | 操作介紹 |
| *p | 復引用迭代器,作為右值 |
| p=p1 | 將一個迭代器賦給另一個迭代器(迭代器指向地址值) |
| p==p1 | 比較迭代器的相等性(比較地址) |
| p!=p1 | 比較迭代器的不等性 |
| 輸出迭代器 | 操作 |
| *p | 復引用迭代器,作為左值 |
| p=p1 | 將一個迭代器賦給另一個迭代器 |
| 正向迭代器 | 提供輸入輸出迭代器的所有功能 |
| 雙向迭代器 | 操作 |
| –p | 前置自減迭代器 |
| p– | 后置自減迭代器 |
| 隨機迭代器 | |
| p+=i | 將迭代器遞增i位 |
| p-=i | 將迭代器遞減i位 |
| p+i | 在p位加i位后的迭代器 |
| p-i | 在p位減i位后的迭代器 |
| p[i] | 返回p位元素偏離i位的元素引用 |
| p<p1 | 如果迭代器p的位置在p1前,返回true,否則返回false |
| p<=p1 | p的位置在p1的前面或同一位置時返回true,否則返回false |
| p>p1 | 如果迭代器p的位置在p1后,返回true,否則返回false |
| p>=p1 | p的位置在p1的后面或同一位置時返回true,否則返回false |
只有順序容器和關聯容器支持迭代器遍歷,各容器支持的迭代器的類別如下:
| vector | 隨機訪問 | 一種隨機訪問的數組類型,提供了對數組元素進行快速隨機訪問以及在序列尾部進行快速的插入和刪除操作的功能。可以再需要的時候修改其自身的大小 |
| deque | 隨機訪問 | 一種隨機訪問的數組類型,提供了序列兩端快速進行插入和刪除操作的功能。可以再需要的時候修改其自身的大小 |
| list | 雙向 | 一種不支持隨機訪問的數組類型,插入和刪除所花費的時間是固定的,與位置無關。 |
| set | 雙向 | 一種隨機存取的容器,其關鍵字和數據元素是同一個值。所有元素都必須具有惟一值。 |
| multiset | 雙向 | 一種隨機存取的容器,其關鍵字和數據元素是同一個值。可以包含重復的元素。 |
| map | 雙向 | 一種包含成對數值的容器,一個值是實際數據值,另一個是用來尋找數據的關鍵字。一個特定的關鍵字只能與一個元素關聯。 |
| multimap | 雙向 | 一種包含成對數值的容器,一個值是實際數據值,另一個是用來尋找數據的關鍵字。一個關鍵字可以與多個數據元素關聯。 |
| stack | 不支持 | 適配器容器類型,用vector,deque或list對象創建了一個先進后出容器 |
| queue | 不支持 | 適配器容器類型,用deque或list對象創建了一個先進先出容器 |
| priority_queue | 不支持 | 適配器容器類型,用vector或deque對象創建了一個排序隊列 |
二、容器
所有容器都支持自定義數據類型,就是結構體。
vector
使用此容器需在程序前加上頭文件#include< vector >。
vector可理解為變長數組,基于倍增思想。當以已申請vector長度為m時,若實際長度n=m,則申請長度為2m的數組,將內容轉移至新地址上,并釋放舊空間;刪除元素時,若n<=m/4,則釋放一半空間。
vector容器能像數組一樣隨機訪問第i個數a[i],但不支持隨機插入.
具體操作如下:
a.size() //返回實際長度(元素個數),O(1)復雜度a.empty() //容器為空返回1,否則返回0,O(1)復雜度a.clear() //把vector清空a.begin() //返回指向第一個元素的迭代器,*a.begin()與a[0]作用相同a.end() //越界訪問,指向vector尾部,指向第n個元素再往后的邊界a.front() //返回第一個元素的值,等價于*a.begin和a[0]a.back() //返回最后一個元素的值,等價于*--a.end()和a[size()-1]a.push_back(x) //把元素x插入vector尾部a.pop_back() //刪除vector中最后一個元素迭代器使用與指針類似,可如下遍歷整個容器
for ( vector<int>::iterator it=a.begin() ; it!=a.end() ; it++ )queue
循環隊列queue需使用頭文件< queue >
queue<int> q; //定義了一個int類型的隊列容器q struct rec{···};queue<rec> q; //定義了一個rec類型的隊列容器q q.push(x); //從隊尾使元素x入隊,O(1) q.pop(x); //使隊首元素出隊,O(1) int x=q.front(); //詢問隊首元素的值,O(1) int y=q.back(); //詢問隊尾元素的值,O(1)priority_queue
優先隊列priority_queue可理解為一個大根二叉堆,必須定義“小于號”,而int,string本身就能比較。同樣需要頭文件< queue >。
其定義方式與queue相似。
可通過插入元素的相反數取出時再取反,或重載“小于號”的方式實現小根堆,通過懶惰刪除法實現隨機刪除操作。
deque
雙端隊列,是一個支持在兩端高效插入或刪除元素的連續線性存儲空間,可像數組一樣隨機訪問,使用前加頭文件< deque >。
q.begin()/q.end() //頭/尾迭代器,與vector類似 q.front()/q.back() //頭/尾元素,與queue類似 q.push_back(x)/q.push_front(x) //從隊尾/隊頭入隊 q.pop_back(x)/q.pop_front(x) //從隊尾/隊頭出隊 q.clear() //清空隊列定義方式
deque<類型> 名稱ps:clear復雜度為O(n),其余為O(1)。
set/multiset
兩容器相似,但set為有序集合,元素不能重復,multiset為有序多重集合,可包含若干相等的元素,內部通過紅黑樹實現,支持的函數基本相同,同樣必須定義“小于號”運算符,頭文件為< set >。
其迭代器不支持隨機訪問,支持星號(*)結束引用,僅支持 ++ 、-- 兩個與算術有關的操作。迭代器it++,則指向從小到大排序的結果中排在it下一名的元素,兩操作時間復雜度均為O(log n)。
定義方式
set<int> demo 定義一個類型為int的set容器 struct rec {int a,b,c;bool operator<(const rec&w){if(a==w.a) return b==w.b?c<w.c:b<w.b;return a<w.a;} };set<rec> ob; 一樣所有排序的容器不重載就出錯map/multimap
map/multimap映射容器的元素數據是由一個Key和一個Value成的,key與映照value之間具有一一映照的關系。
map/multimap容器的數據結構也采用紅黑樹來實現的,map插入元素的鍵值不允許重復,類似multiset,multimap的key可以重復。比較函數只對元素的key進行比較,元素的各項數據只能通過key檢索出來。雖然map與set采用的都是紅黑樹的結構,但跟set的區別主要是set的一個鍵值和一個映射數據相等,Key=Value。
map<first,second> a; //map,會按照first(鍵值)排序(查找也是);map/multimap用法
頭文件
map成員函數
begin() //返回指向 map 頭部的迭代器 clear() // 刪除所有元素 count() //返回指定元素出現的次數 empty() // 如果 map 為空則返回 true end() //返回指向 map 末尾的迭代器 erase() // 刪除一個元素 find() // 查找一個元素 insert() //插入元素 key_comp() //返回比較元素 key 的函數 lower_bound() //返回鍵值>=給定元素的第一個位置 max_size() //返回可以容納的最大元素個數 rbegin() //返回一個指向 map 尾部的逆向迭代器 rend() //返回一個指向 map 頭部的逆向迭代器 size() //返回 map 中元素的個數 swap() //交換兩個 map創建map對象
#include<iostream> #include<map> using namespace std; map<int,char>mp;//定義map容器創建結構體map對象
struct student{ int birth; string name; }; int id; typedef map<int,student> Student;// 這里相當于給map<int,student> 起了個別名Student,后續代碼均可以用student代替map<int,student> 使用。插入結構體對象
接上文代碼
棧(stack)
1.定義:
棧是一種只能在某一端插入和刪除數據的特殊線性表。他按照先進先出的原則存儲數據,先進的數據被壓入棧底,最后進入的數據在棧頂,需要讀數據的時候從棧頂開始彈出數據(最后被壓入棧的,最先彈出)。因此棧也稱先進后出表。
允許進行插入刪除操作的一端稱為棧頂,另一端稱為棧底。棧底固定,棧頂浮動。插入元素稱為進棧,刪除一個元素稱為進棧,棧內元素為零稱為空棧。
2.stack成員函數
List
定義:List類表示可通過索引訪問的對象的強類型列表,提供用于對列表進行搜索、排序和操作的方法。
作用:
泛型最常見的用途是泛型集合
我們在創建列表類時,列表項的數據類型可能是int,string或其它類型,如果對列表類的處理方法相同,
就沒有必要事先指定數據類型,留待列表類實例化時再指定。相當于把數據類型當成參數,這樣可以最
大限度地重用代碼,保護類型的安全以及提高性能。
定義 list<類型> 名稱
成員函數
bitset
bitset可看作一個多位二進制數,每8位占用1個字節,相當于采用了狀態壓縮的二進制數組,并支持基本的位運算。一般以32位整數的運算次數為基準估算運行時間,n位bitset執行一次的位運算復雜度可視為n/32,效率較高。頭文件< bitset >。
同樣具有~,&,|,^,<<,>>操作符,==,!=可比較二進制數是否相等
三、算法
查找算法(9個):判斷容器中是否包含某個值
(可以去看看C++primer學學別的,但是我認為太多了沒必要)
1.count:
利用等于操作符,把標志范圍內的元素與輸入值比較,返回相等元素個數。
2.count_if:
利用輸入的操作符,對標志范圍內的元素進行操作,返回結果為true的個數。
補充:捕獲值列表,是允許我們在Lambda表達式的函數體中直接使用這些值,捕獲值列表能捕獲的值是所有在此作用域可以訪問的值,包括這個作用域里面的臨時變量,類的可訪問成員,全局變量。捕獲值的方式分兩種,一種是按值捕獲,一種是按引用捕獲。顧名思義,按值捕獲是不改變原有變量的值,按引用捕獲是可以在Lambda表達式中改變原有變量的值。
[捕獲值列表]:
1、空。沒有使用任何函數對象參數。
2、=。函數體內可以使用Lambda所在作用范圍內所有可見的局部變量(包括Lambda所在類的this),并且是值傳遞方式(相當于編譯器自動為我們按值傳遞了所有局部變量)。
3、&。函數體內可以使用Lambda所在作用范圍內所有可見的局部變量(包括Lambda所在類的this),并且是引用傳遞方式(相當于編譯器自動為我們按引用傳遞了所有局部變量)。
4、this。函數體內可以使用Lambda所在類中的成員變量。
5、a。將a按值進行傳遞。按值進行傳遞時,函數體內不能修改傳遞進來的a的拷貝,因為默認情況下函數是const的。要修改傳遞進來的a的拷貝,可以添加mutable修飾符。
6、&a。將a按引用進行傳遞。
7、a, &b。將a按值進行傳遞,b按引用進行傳遞。
8、=,&a,&b。除a和b按引用進行傳遞外,其他參數都按值進行傳遞。
9、&, a, b。除a和b按值進行傳遞外,其他參數都按引用進行傳遞。
3.equal_range:
功能類似equal,返回一對iterator,第一個表示lower_bound,第二個表示upper_bound。
4.find:
利用底層元素的等于操作符,對指定范圍內的元素與輸入值進行比較。當匹配時,結束搜索,返回該元素的一個InputIterator。
補充
InputIterator是用于輸入的Iterator
OutputIterator是用于輸出的Iterator
ForwardIterator是InputIterator,同時可以保證++運算不會使之失效
RandomIterator是ForwardIterator,同時具有+,-,+=,-=等運算及各種比較操作
5.find_end:
在指定范圍內查找"由輸入的另外一對iterator標志的第二個序列"的最后一次出現。找到則返回最后一對的第一個ForwardIterator,否則返回輸入的"另外一對"的第一個ForwardIterator。重載版本使用用戶輸入的操作符代替等于操作。
6.find_first_of:
在指定范圍內查找"由輸入的另外一對iterator標志的第二個序列"中任意一個元素的第一次出現。重載版本中使用了用戶自定義操作符。
7.find_if:
使用輸入的函數代替等于操作符執行find。返回的是迭代器,為了是大家更明白的理解,減去第一個元素的位置,就相當于得到了下標;
8.lower_bound:
返回一個ForwardIterator,指向在有序序列范圍內的可以插入指定值而不破壞容器順序的第一個位置。重載函 數使用自定義比較操作。
在一個有序的范圍內時間復雜度為log2n,普遍適用于二分算法。
跟3.equal_range的用法一樣不過這個返回的是first
9.upper_bound:
返回一個ForwardIterator,指向在有序序列范圍內插入value而不破壞容器順序的最后一個位置,該位置標志 一個大于value的值。重載函數使用自定義比較操作。跟3.equal_range的用法一樣不過這個返回的是second;
排序和通用算法(7個):提供元素排序策略
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的值。
刪除修改復制(12個):簡單操作區間元素
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。重載版本使用 自定義的比較操作。
//常以此方式使用,但時間復雜度N!這個。。。。 do {//操作 }while((next_permutation(首地址,第一個不合法地址)生成和異變算法(3個)
fill:
將輸入值賦給標志范圍內的所有元素。
區別于memset,memset是按位賦值,只能賦每位值相同值。
memset(首地址,value,(字節數)常用sizeof()獲取)fill_n:
將輸入值賦給first到first+n范圍內的所有元素。
// 從開始以此賦值,3個5 fill_n(首地址,3,5);transform:
將輸入的操作作用與指定范圍內的每個元素,并產生一個新的序列。重載版本將操作作用在一對元素上,另外一個元素來自輸入的另外一個序列。結果輸出到指定容器。
關系算法(6個)
equal:
如果兩個序列在標志范圍內元素都相等,返回true。重載版本使用輸入的操作符代替默認的等于操作符。
includes:
判斷第一個指定范圍內的所有元素是否都被第二個范圍包含,使用底層元素的<操作符,成功返回true。重載版本使用用戶輸入的函數。
max:(很多人問我,這不是cmath嗎,呃。。。。。不是)
返回兩個元素中較大一個。重載版本使用自定義比較操作。
max_element:
返回一個ForwardIterator,指出序列中最大的元素。重載版本使用自定義比較操作。
max_element(a, a+6) 返回一個最大值位置指針min:
返回兩個元素中較小一個。重載版本使用自定義比較操作。
min(3,5)的值是5;min_element:
返回一個ForwardIterator,指出序列中最小的元素。重載版本使用自定義比較操作。
集合算法(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:
對指定范圍內的序列重新排序,它假設該序列是個有序堆。重載版本使用自定義比較操作。
總結
以上是生活随笔為你收集整理的学了C++不会STL,简直少了左膀右臂的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 快手授权管理在哪里找
- 下一篇: 买车补贴5000元!湖南推出“稳增长20