-
C++中除了面向對象的編程思想外,還有另一種就是泛型編程
-
主要用到的技術就是模板
模板機制的分類:
-
函數模板
-
類模板
函數模板
作用:建立一個通用函數,其函數返回值類型和形參類型可以不具體定制,用虛擬的類型來表示
關鍵字:template
語法:
template <typename T> // template <class T>
函數聲明或者定義
-
template:聲明創建模板
-
typename:表明后面的符號是一種數據類型,也可以用class代替
-
T:通用的數據類型,名稱可以替換,通常為大寫字母
意義:將類型參數化,提高代碼通用性。
使用方法:
-
自動類型推導
-
顯示指定類型
注意事項:
-
自動類型推導,無論有幾個 T,其必須要推導出一致的數據類型,才可以使用
-
函數模板必須要確定 T 的數據類型,才可以使用
與普通函數的區別:
-
普通函數調用時可以發生自動類型轉換,也就是隱式轉換
-
函數模板只有在調用顯示指定類型才會發生隱式轉換,用自動類型推導就不會
示例:
調用規則
-
如果普通函數和函數模板都實現了,優先使用普通函數
-
可以通過空模板參數列表強制調用函數模板
-
函數模板可以以發生函數重載
-
如果函數模板可以更好的匹配,那肯定是優先使用函數模板啦
示例:
函數模板的局限性
一些特定的數據類型,函數模板就處理不了
示例:
-
為了解決這些問題,C++提供了模板的重載,為特定的數據類型提供具體化的模板
-
利用具體化的模板,可以解決類型自定義的通用性
-
但是模板其實不用去寫,可以在STL中調用系統提供的模板
語法:
template<> 返回值類型 函數名(參數1,參數2,···)
示例:
類模板
作用:建立一個通用的類,但是類中的成員變量類型未知,用一個虛擬的類型來表示
語法:
template<typename T> 類
-
template:聲明創建一個模板
-
typename:表明后面的 T 是一種數據類型,typename 也可以用class替代
-
T:通用的數據類型
與函數模板的區別:
-
類模板在使用的時候,沒有自動類型推導的方式
-
類模板在模板參數列表中可以有默認參數類型
示例:
類模板成員函數創建時機
-
普通類中的成員函數,在一可以就可以創建
-
類模板中的成員函數,在函數調用時才創建
示例:
類模板對象做函數參數
作用:用模板實例出的對象來當做函數參數傳入
傳入方式:
-
指定傳入的類型:直接顯示對象的數據類型
-
參數模板化:將對象中的參數變為模板進行傳遞
-
整個類模板化:將整個對象進行模板化,傳遞下去
一般而言第一種傳遞方式比較常見;
第二種和第三種,其實有點像函數模板和類模板結合使用;
使用函數 typeid(temp) 可獲知一個參數 temp 的類型;
示例:
類模板與繼承
當類模板碰到繼承時:
-
當子類繼承的父類是一個類模板時,子類在聲明時要指定父類 T 的類型
-
如果不指定,編譯器就無法給子類分配內存
-
要想靈活指定父類中 T 的類型,子類也必須為類模板
語法:
template<class T1 , class T2>
class 子類:繼承方式 父類<T2>
{
//T1 通用類型留給子類自己用
}
示例:
類模板成員函數的類外實現
類外實現的方法:
-
類內聲明,類外寫函數定義
-
類外寫函數時,作用域需要加上模板參數列表
語法:
template<class T>
返回值類型 作用域<T>::成員函數()
//作用域要加上模板參數列表<T>,不管傳參和函數內部有沒有用到 T ,<T> 都要寫出來
{
}
示例:
分文件編寫
在使用類模板過程中,進行分文件編寫會出現一些問題:
一般的分文件編寫:
.h:寫類聲明和成員函數定義
.cpp:寫類中成員函數的實現
x.cpp:寫主函數和應用功能
原因:類模板的成員函數在主函數調用的時候才創建,所以會導致預處理時鏈接不到
解決辦法(建議用第二種):
-
直接包含.cpp源文件(將x.cpp中的#include".h">改成#include".cpp",而.cpp中也有包含頭文件,這樣改,就是在跑主函數之前,將聲明和實現都跑了一遍)
-
將聲明和實現寫在同一個文件中,后綴名改成.hpp(.hpp是約定俗成的名字,不是強制的,但大家都這么寫)
兩種方法,目的都是在跑主函數之前,將聲明和實現都先跑了一遍。
類模板與友元
類模板和友元配合成的全局函數的類內實現和類外實現:
-
類內實現:直接在類內聲明友元即可(建議這個,比較簡單)
-
類外實現:需要提前讓編譯器知道全局函數的存在(有點復雜,不建議)
示例:
STL
-
之所以有C++的面向對象和泛型編程,目的就是提升可重復性
-
STL的誕生,就是為了建立一套數據結構和算法的標準,提高可重復利用性
STL基本概念
-
STL,即標準模板庫
-
從廣義上分為:容器、算法、迭代器
-
從細分上分為:容器、算法、迭代器、仿函數、適配器(配接器)、空間配置器
-
容器和算法通過迭代器進行無縫連接
-
STL所有的代碼都運用到了函數模板和類模板
STL六大組件
六大組件就是上線說到的:容器、算法、迭代器、仿函數、適配器(配接器)、空間配置器
-
容器:各種數據結構,如vector、list、deque、set、map等,用來存放數據
-
算法:各種常用算法,如sort、find、copy、for_each等
-
迭代器:容器和算法之間的鏈接器
-
仿函數:類似函數,可作為算法的某種策略
-
適配器:一種用來修飾容器或者仿函數或者迭代器的東西
-
空間配置器:負責空間的分配和管理
容器
作用:存放數據,將廣泛使用的數據結構給實現出來
常用的數據結構:數組、鏈表、樹、棧、隊列、集合、映射表等
容器的分類:
-
序列式容器:強調值的位置,每個元素都有固定的位置
-
關聯式容器:二叉樹結構,元素之間沒有嚴格的物理上的順序關系
算法
作用:問題的解法,即用有限的步驟,解決邏輯上的難題
算法的分類:
-
質變算法:運算中更改區間內元素的內容,如拷貝、替換、刪除等
-
非質變算法:運算中不會更改區間內元素的內容,如查找、計數、遍歷、尋值等
迭代器
作用:容器和算法之間的鏈接器,即就是提供一種方法,既能依序尋找容器內某個元素,又不暴露容器內部的表示方法
-
每個容器都有自己專屬的迭代器
-
迭代器的使用方法類似于指針
-
最常用的是雙向迭代器和隨機訪問迭代器
迭代器的種類:
|
種類 |
功能 |
支持運算 |
|---|---|---|
|
輸入迭代器 |
對數據的只讀訪問 |
只讀,支持++、==、!= |
|
輸出迭代器 |
對數據的只寫訪問 |
只寫,支持++ |
|
前向迭代器 |
對數據的向前操作 |
讀寫,支持++、==、!= |
|
雙向迭代器 |
對數據的向前和向后操作 |
讀寫,支持++、-- |
|
隨機訪問迭代器 |
訪問任何數據,功能最強 |
讀寫,支持++、--、[n]、-n、<、<=、>、>= |
String容器
基本概念
-
string是C++風格的字符串,但是本質上是一個類
-
String是內部封裝了char類型,管理string這個類,用的是char*的容器
-
包含頭文件#include<string>
特點
-
string內部封裝了很多成員函數方法,比如find查找,copy復制,delete刪除,replace替換,insert插入等等
-
string管理char*所分配出來的內存,不用擔心復制越界內存和取值越界,也不用擔心溢出或者碎片,這些由容器內部統一管理
string構造函數
-
string();無參構造,主要用來創建一個空字符串
-
string(const char* s); 用來初始化一個字符串
-
string(const string& str); 用一個string對象來初始化另一個string對象
-
string(int n,char c); 初始化n個字符c
-
以上構造函數沒有什么可比性,根據實際情況靈活運用即可
示例:
賦值操作
作用:給string字符串賦值
函數原型:
-
string& operator= ( const char *s ) ; 將char *類型的字符串賦值給當前字符串
-
string& operator= ( const string &s ) ; 將string類型字符串賦值給當前字符串
-
string& operator= ( char c ) ; 將字符c賦值給當前字符串
-
string& assign ( const char*s ) ; 將char *類型字符串賦值給當前字符串
-
string& assign ( const char *s, int n ) ; 將char *類型的字符串的前n個字符賦值給當前字符串
-
string& assign ( const string &s ) ; 將const類型的字符串賦值給當前字符串
-
string& assign ( int n,char s ) ; 將n個字符s賦值給當前字符串
示例:
字符串拼接
作用:就是在字符串末尾再拼接一段字符串
函數原型:
-
string& operator+ ( const char *c ) ; //將char*類型的字符串拼接到當前字符串末尾
-
string& operator+ ( const char c ) ; //將字符c拼接到當前字符串末尾
-
string& operator+ ( const string& str ) ; //將string類型的字符串拼接到當前字符串末尾
-
string& append ( const char *s ) ; //將char*類型的字符串拼接到當前字符串末尾
-
string& append ( const char *s , int n ); //將char*類型字符串的前n個字符拼接到當前字符串末尾
-
string& append ( const string &s ) ; // 將string類型額字符串拼接到當前字符串末尾
-
string& append ( const string &s, int pos , int n ); //將string類型的字符串從pos個開始的n個字符拼接到當前字符串末尾
示例:
字符串的查找和替換
作用:
-
查找:查找指定的字符串是否存在
-
替換:在指定的位置替換字符串
函數原型:
-
int find ( const string& str , int pos = 0 ) const ; //查找str第一次出現的位置,從pos開始查找
-
int find ( const char* s , int pos = 0 ) const ; //查找 s 第一次出現的位置,從pos開始查找
-
int find ( const char* s ,int pos , int n ) const ; //查找s的前n個字符第一次出現的位置,從pos開始查找
-
int find ( const char c , int pos = 0 ) const ; //查找字符串 c 第一次出現的位置,從pos開始查找
-
int rfind ( const string& str , int pos = npos ) const; //查找str最后一次的位置,從pos開始查找
-
int rfind ( const char* s , int pos = npos ) const ; //查找 s 最后一次出現的位置,從pos開始查找
-
int rfind ( const char* s , int pos , int n) const; //查找 s 的前n個字符最后一次的位置,從pos開始查找
-
int rfind ( const char s , int pos = 0 ) const ; //查找字符 s 最后一次出現的位置,從pos開始查找
-
string& replace ( int pos , int n , const string& str) ; //從pos開始的n個字符,替換成字符串str
-
string& replace ( int pos , int n , const char* s); //從pos開始的n個字符,替換成字符串 s
特點:
-
find是從左往右找,rfind是從右往左找,找到了返回下標位置,找不到返回 -1
-
replace會把替換字符串全部替換進去,不管你指定多少個字符
示例:
字符串比較
作用:字符串之間的比較
特點:
-
以其中的字符的ASCII值得方式進行比較
-
> 返回 1
-
< 返回 -1
-
= 返回 0
-
主要是用來比較兩個字符串是否一樣,比較大小沒有什么意義
函數原型:
-
int compare ( const string& s) const ; //與string類型的字符串進行比較
-
int compare ( const char s ) const ; //與char*類型的字符串進行比較
示例:
字符存取
對單個字符進行存取有兩種方法:
-
通過 [ ] 方式進行存取
-
通過at函數方式進行存取
函數原型:
-
char& operator[](int n) ; //通過[]方式存取
-
char& at(int n); //通過at方式存取
示例:
字符的插入和刪除
作用:對字符串中進行插入和刪除字符的操作
函數原型:
-
string& insert ( int pos , const char* s ) ; //從pos位置開始插入字符
-
string& insert ( int pos , const string& s); //從pos位置開始插入字符
-
string& insert ( int pos , int n, char s); //從pos位置開始,插入n個字符s
-
string& erase( int pos , int n = npos ) ; //從pos位置開始,刪除n個字符
-
參數pos的位置,都是從下標0開始的
示例:
字符串子串
作用:從字符串中截取想要的子串
函數原型:
-
string substr( int pos , int n = npos) const ; //從pos位置開始,截取n個字符
示例:
Vector容器
基本概念
-
vector數據結構與數組非常相似,但是只能進行尾部的插入和刪除,所以也被稱為單端數組
-
vector容器的迭代器是支持隨機訪問的迭代器,功能最強大的迭代器之一
-
包含頭文件 #include<vector>
與普通數組的區別
-
數組是靜態空間
-
vector可以動態擴展
-
動態擴展并不是在原空間上續接新空間,而是尋找更大的空間,將原數據拷貝過去,在新空間后續接空間,釋放源空間
構造函數
作用:創建vector容器
函數原型:
-
vector <T> v ; //默認構造函數,T 是數據類型 , v是容器名字
-
vector ( v.begin() , v.end() ) ; //將v.[ begin() , end() ) 區間中的元素拷貝給本身
-
vector ( n , a ) ; //構造函數將 n 個 a 數值拷貝給本身
-
vector ( const vector &ver ) ; //拷貝構造函數
示例:
vector賦值
作用:給vector容器進行賦值操作
函數原型:
-
vector& operator= ( const vector &vst ) ; //重載方式進行賦值
-
assign ( begin , end ) ; //將 [ begin , end )區間內的數值賦值給本身
-
assign (n , A) ; //將n個字符A賦值給本身
示例:
容量和大小
作用:獲取vector容器的容量和大小參數
函數原型:
-
empty ( ) ; //判斷是否為空
-
capacity ( ) ; //獲取容器的容量
-
size ( ) ; //獲取元素個數
-
resize ( int num ) ; //重新指定容器長度,容器變長,超出的用0表示;容器變短,超出的被刪除
-
resize ( int num,int elem ) ; //重新指定容器元素,容器變長,超出的用elem表示,變短則超出的被刪除
示例:
插入和刪除
作用:在容器中插入元素和刪除元素
函數原型:
-
push_back ( ) ; //尾部插入
-
pop_back ( ) ; //刪除尾部最后一個元素
-
insert ( const_iterator pos , elem ) ; //插入元素elem,第一個參數是迭代器指向位置
-
insert (const_iterator pos , int num , elem ) ; //插入num個elem數值,第一個參數是迭代器指向位置
-
erase ( const_iterator pos ); //刪除元素,第一個參數是迭代器指向位置
-
erase ( const_iterator begin , const_iterator end ); //刪除從頭到尾的元素
-
clear ( ); //刪除容器內全部元素
示例:
數據存取
作用:獲取容器中的數據
函數原型:
-
at ( int idx ) ; //返回索引下的元素
-
operator[ ] ; //重載方式返回索引下的元素
-
front ( ) ; //獲取容器第一個元素
-
back ( ) ; //獲取容器中最后一個元素
示例:
容器互換
作用1:實現兩個容器之間的元素互換
作用2:用于收縮容器容量(原理就是創建一個小容量的容器與本身的大容量容器互換)
函數原型:
-
swap( vec ) ; //將容器vec中的元素與本身互換
示例:
預留內存
作用:在一開始就開辟出足夠的空間,減少動態擴展的次數
原理:因為一旦容器輸入數據量較大的時候,編譯器會根據內存實際情況時不時進行動態擴展,動態擴展次數一旦多了,操作時間就長了,所以最好是在一開始就預留足夠多的空間,將動態擴展次數維持為1次。
函數原型:
-
reserve ( int len ) ; //預留len個元素長度,預留位置不初始化,也不可以訪問
示例:
vector排序
-
作用:利用算法對容器內元素進行排序
-
需要包含算法頭文件 #include <algorithm>
-
對于隨時訪問的迭代器都可以使用該排序函數
函數原型:
-
sort( iterator begin , iterator end ) ; // 對begin和end之間的元素進行從小到大排序
示例:
deque容器
-
與數組類似,可以進行頭部和尾部的插入和刪除,因為也被稱為雙端容器
-
deque容器的迭代器也是支持隨機訪問的
-
頭文件#include <deque>
deque與vector的區別:
-
vector容器只能尾部插入和刪除,因為對于頭部操作效率很低,數據量越大越低
-
deque容器頭部的插入和刪除速度比vector快多了
-
vector和deque內部結構不同,導致元素的速度vector會更快,導致deque沒有容量限制,可以無限擴張
-
二者的迭代器都支持隨機訪問,是最強大的迭代器之一
?
內部工作原理
-
deque內部有一個中控器,用于記錄每段緩沖區的地址,緩沖區中放置真實數據
-
中控器+緩沖區,使得deque看起來像是一塊連續的內存
?
構造函數
作用:創建deque容器
函數原型:
-
deque<T> d ; //默認構造函數,T表示數據類型
-
deque( begin , end ) ; //將容器[ begin , end )區間內的數據拷貝給本身
-
deque( count , elem ) ; //將count個elem數值拷貝給本身
-
deque ( const deque& d ) ; //拷貝構造函數,將容器數據整個拷貝給本身
示例:
賦值操作
作用:給deque容器進行賦值
函數原型:
-
deque& operator=( const deque& d) ; //重載方式進行賦值
-
assign ( begin , end ); //將[ begin , end )區間內的數據賦值給容器
-
assign ( count , elem ); //將count個elem數值賦值給容器
示例:
獲取大小,沒有容量限制
-
作用:獲取deque內部的元素長度
-
由于中控器+緩沖區的內部結構,導致deque是沒有容量限制的,理論上內存可以無限擴張,所以沒有獲取容量的函數
函數原型:
-
empty( ) ; // 判斷容器是否為空
-
size( ) ; //獲取元素個數
-
resize ( num ) ; //重新指定容器長度,若容器變長,以默認值0填充新位置;若長度變短,超出部分刪除
-
resize ( num , elem ) ; //重新指定容器長度,若容器變長,以elem填充新位置,若變短,超出部分刪除
示例:
插入和刪除
作用:在容器兩端進行插入和刪除新數據
函數原型:
-
push_back( elem); // 尾部插入數據elem
-
push_front( elem); //頭部插入數據elem
-
pop_back( ); //刪除最后一個元素
-
pop_front( ); //刪除第一個元素
-
insert( pos ,elem); //在迭代器位置pos插入數據elem
-
insert( pos , n, elem ); //在迭代器位置pos插入n個elem數據
-
insert( pos, begin, end ); //在迭代器位置pos插入[begin , end)區間內的數據
-
erase( pos); //刪除迭代器位置pos的數據
-
erase( begin , end ); //刪除從begin到end之間的數據
-
clear(); //刪除容器內所有元素
示例:
數據存取
作用:對deque容器中的數據進行存取
函數原型:
-
operator[ ] ; //重載方式返回索引idx的數據
-
at( int dix ) ; //at()返回索引idx的數據
-
front( ) ; //返回第一個元素
-
at( ) ; //at()返回索引idx的數據
示例:
deque排序
-
作用:利用算法對容器內元素進行排序
-
需要包含算法頭文件 #include <algorithm>
-
對于隨時訪問的迭代器都可以使用該排序函數,包括vector容器
函數原型:
-
sort( iterator begin , iterator end ) ; // 對begin和end之間的元素進行從小到大排序
示例:
stack容器
-
stack容器是一種前進后出的數據結構,又稱為棧容器
-
該容器只有頂端的元素才可以給外界獲取
-
該容器不允許有遍歷行為
-
包含頭文件 #include <stack>
?
構造函數
函數原型:
-
stack<T> stk ; //默認構造函數
-
stack( const stack &stk ) ; // 拷貝構造函數
賦值操作
函數原型:
-
stack& operator=( const stack& stk ) ; //重載方式進行賦值
數據存取
函數原型:
-
push( elem ) ; //向棧頂添加元素
-
pop( ) ; //刪除棧頂第一個元素
-
top( ) ; //返回棧頂元素
大小獲取操作
函數原型:
-
empty( ) ; //判斷容器是否為空
-
size( ) ; // 返回容器的大小
示例:
queue容器
-
queue容器是一種先進先出的數據結構,又稱為隊列容器
-
允許從一段添加元素,另一端刪除元素
-
只有隊尾和隊頭可以被外界使用,因此不允許有遍歷行為
-
包含頭文件 #include<queue>
構造函數
函數原型:
-
queue<T> que ; //默認構造函數
-
queue( const queue& que ) ; //拷貝構造函數
賦值操作
函數原型:
-
queue& operator=( const queue& que ) ; //重載方式賦值
數據存取
函數原型:
-
push( elem ) ; //往隊尾添加元素
-
pop( ) ; //刪除隊頭的元素
-
back( ) ; //返回最后一個元素
-
front( ) ; //返回第一個元素
大小獲取
函數原型:
-
empty( ) ; //判斷隊列是否為空
-
size( ) ; // 判斷隊列的大小
示例;
list容器
-
list容器是一種雙向循環的數據結構,又稱為鏈式容器
-
內部結構并不是連續的內存,迭代器不能隨訪問,只能前移和后移,屬于雙向迭代器
-
包含頭文件 #include<list>
-
動態存儲分配,不會存在內存浪費和溢出的問題
-
隨機訪問,插入和刪除非常方便
-
占用空間比較大,遍歷的消耗非常大
構造函數
作用:創建一個list容器
函數原型:
-
list<T> lst ; //默認構造函數
-
list( begin , end ) ; //將區間 [ begin ,end)之間的元素拷貝給本身
-
list( n , elem ) ; // 將 n個elem拷貝給本身
-
list( const list &lst) ; // 拷貝構造函數
賦值與交換
作用:給list容器賦值,以及交換list容器
函數原型:
-
list& operator=( const list& lst ) ; // 重載方式進行賦值
-
assign( begin() , end() ) ; //將區間[ begin , end)之間的元素賦值給本身
-
assign( n , elem ) ; //將 n 個 elem賦值給本身
-
swap( lst ) ; // 將容器 與 本身的元素互換
示例:
大小操作
作用:獲取容器list的長度
函數原型:
-
size( ) ; //返回元素個數
-
empty( ) ; // 判斷是否為空
-
resize( num ) ; //重新指定容器長度,容器變長,以默認值0填充,容器變短,超出的元素被刪除
-
resize( num , elem ) ; //重新指定容器長度,容器變長,以數值elem填充,容器變短,超出的元素被刪除
示例:
插入和刪除
作用:對list容器進行元素插入和刪除
函數原型:
-
push_back( elem ); //尾部插入數據
-
push_front( elem ); //頭部插入數據
-
pop_back(); //刪除最后一個元素
-
pop_front(); //刪除第一個元素
-
insert( pos, elem ); //在迭代器pos位置插入數值elem
-
insert( pos , n , elem ); //在迭代器pos位置插入n個elem
-
insert( pos , begin , end ); //在迭代器pos位置插入從begin到end之間的元素
-
erase( pos ); //刪除迭代器pos位置的元素
-
erase( begin , end ); //刪除迭代器[ begin , end ) 之間的元素
-
remove( elem ); //刪除容器中與elem相同的所有元素
示例;
數據存取
-
存取方式不是[]獲取,也不是at()獲取
-
因為list容器本質是鏈表,既不是連續的內存,迭代器也不支持隨機訪問
函數原型:
-
front(); // 返回第一個元素
-
back(); // 返回最后一個元素
示例:
反轉和排序規則
作用:將容器中的元素反轉,以及對元素進行排序
函數原型:
-
reverse(); //容器元素進行反轉
-
sort(); //容器元素進行從小到大排序,沒有迭代器參數,所以這個是內部成員函數,不是標準算法
-
//對于定義數據類型,必須要指定排序規則(高級排序),否則編譯器是不知道怎么排的
示例:
set/multiset容器
-
在set/multiset容器中,所有的元素都會在插入時自動排序,默認從小到大
-
兩者屬于關聯式容器,內部結構是用二叉樹實現的
-
兩者的頭文件都是 #include<set>
set和multiset的區別:
-
set容器不允許有重復的元素出現,即使強制插入重復元素,插入也會失敗
-
multiset容器可以有重復的元素出現
set的構造函數
作用:創建set容器
函數原型:
-
set<T> st ; // 默認構造函數
-
set(const set& st) ; //拷貝構造函數
set的賦值函數
函數原型:
-
set& operator( const set& st); // 函數重載實現賦值操作
set的插入和刪除
函數原型:
-
insert( elem ) ; // 插入只有insert()方式,不能指定位置,因為會自動排序
-
erase(pos) ; // 刪除迭代器pos位置的元素
-
erase ( elem ); //刪除數值為elem的元素
-
erase( begin , end ); //刪除[ begin,end)之間的元素
-
clear(); //清除所有元素
set的大小和交換
-
作用:統計容器的大小以及交換set容器
-
沒有重新指定容器大小的操作,因為會有默認值填充位置,而set容器中不能出現重復的元素
函數原型:
-
size( ); //返回容器中元素個數
-
empty( ); //判斷容器是否為空
-
swap( ); // 交換兩個集合容器中的數據
set的查找和統計
作用:對set容器進行數據查找以及數據統計
函數原型:
-
find( key ); //查找一個元素是否存在,存在則返回元素迭代器位置,不存在返回set.end()
-
cout( key ); //統計key的元素個數,對于set而言不是0就是1,因為不允許有重復元素
示例:
set和multiset的區別
-
set不可以插入重復數據,而multiset可以
-
set插入數據會返回插入結果,同時也是這樣檢測是不是重復元素
-
multiset插入數據不會檢測,因此可以插入重復數據
set.insert()的函數原型:
-
_Pairib insert( value_type&& _Val) ;
-
using _Pairib = pair<inerator , bool>; //set.insert()的返回值類型是對組,返回迭代器位置和插入結果
multiset.insert()的函數原型:
-
iterator insert(value_type&& _Val); //multiset.insert()返回值類型只有迭代器位置,沒有檢測結果
示例:
pair對組創建
作用:成對出現的數據,可以返回兩個數據
創建方法的函數原型:
-
pair<type , type> p (value1, value2 );
-
pair<type , type> p = make_pair( value1, value2 );
示例:
set容器排序
-
作用:set容器排序是默從小到大,但是可以可以通過仿函數來改變排序規則
-
要在插入數據之前就指定排序規則
-
如果是自定義數據類型,一定要指定排序規則
示例1:指定排序規則——內置數據類型
示例2:指定排序規則——自定義數據類型
map/multimap容器
-
map/multimap都是關聯式容器,內部結構是二叉樹
-
map容器中的元素全是pair對組
-
pair中第一個元素為key(鍵值,起到索引作用),第二個元素為value(實值)
-
所有的元素都會根據元素的key鍵值自動排序,默認從小到大
-
可以根據鍵值快速找到value值,高效率高性能
-
map/multimap兩者的頭文件都是#include<map>
map和multimap的區別:
-
map容器中不允許有重復的key值元素
-
multimap容器中允許有重復的key值元素
map的構造函數
函數原型;
-
map<T1 , T2> mp ; // 默認構造函數
-
map<const map& mp> ; // 拷貝構造函數
map的賦值函數
函數原型:
-
map& operator=( const map& mp) ; // 重載等號操作符進行賦值操作
map的大小和交換
函數原型:
-
size(); // 返回元素個數
-
empty(); // 判斷容器是否為空
-
swap(); // 交換兩個map容器
map的插入和刪除
函數原型:
-
insert(elem); // 插入元素,地址沒法自定義,因為會自動排序
-
erase(key); // 刪除key值的元素
-
erase(pos); // 刪除迭代器pos位置的元素
-
erase(begin , end); // 刪除區間為[begin,end)之間的元素
-
clear(); // 清除容器中所有元素
map的查找和統計
函數原型:
-
find( key ); //查找元素是否存在,存在則返回元素迭代器,不存在則返回map.end() ;
-
count( key ); //返回鍵值為key的元素的個數,對于map,不是0就是1,因為不允許出現重復元素
示例:
map容器排序
-
作用:利用仿函數,改變排序規則
-
排序規則一定要在插入數據前指定
示例:
函數對象/仿函數
-
本質上是一個類,重載函數調用運算符的類,其創建的對象也就被稱為函數對象
-
因為函數對象在發生重載時,就像函數調用一樣,所以也叫做仿函數
-
說白了就是一個對象,一個可以當函數用的對象
特點:
-
函數對象在使用時跟函數差不多,可以有參數,也可以有返回值
-
函數對象可以有自己的狀態,函數沒有
-
函數對象可以作為參數傳遞
示例:
謂詞
-
返回bool類型的仿函數,就稱為謂詞
-
如果operator()接受一個參數,就是一元謂詞
-
如果operator()接受兩個參數,就是二元謂詞
一元謂詞
-
如果operator()接受一個參數,就是一元謂詞
示例:
二元謂詞
-
如果operator()接受兩個參數,就是二元謂詞
示例:
內建函數對象
-
STL內建了一些已經封裝好了的函數對象
-
這些對象是由仿函數所產生的,用法和一般對象一樣
-
需要加入頭文件#include<functional>
-
內建函數對象是已經寫好的標準算法入口,愿意你就用,不愿意就自己寫一個
分類:
-
算術仿函數
-
關系仿函數
-
邏輯仿函數
算術仿函數
作用:實現四則運算
函數原型:
-
template<class T> T plus<T> // 加法仿函數,二元運算
-
template<class T> T minus<T> //減法仿函數,二元運算
-
template<class T> T multiplies<T> //乘法仿函數,二元運算
-
template<class T> T divides<T> //除法仿函數,二元運算
-
template<class T> T modulus<T> //取模仿函數,二元運算
-
template<class T> T negate<T> //取反仿函數 ,一元運算
示例:
關系仿函數
作用:實現關系對比
函數原型:
-
template<class T> bool equal_to<T> // 等于
-
template<class T> bool not_equal_to<T> //不等于
-
template<class T> bool greater<T> //大于
-
template<class T> bool greater_equal<T> //大于等于
-
template<calss T> bool less<T> //小于
-
template<class T> bool less_equal<T> //小于等于
示例:不用自己寫的仿函數,用內建函數對象來改變排序規則
邏輯仿函數
作用:實現邏輯運算
函數原型:
-
template<class T> bool logical_and<T> // 邏輯與
-
template<class T> bool logical_or<T> //邏輯或
-
template<class T> bool logical_not<T> //邏輯非
示例:用邏輯非操作將容器v1的元素取反并搬運到容器v2中
先更新到這兒吧,需要后面在補充。
希望以上內容可以幫助到大家。
祝各位生活愉快。
?

一萬字梳理出C++所有知識點






浙公網安備 33010602011771號