c++ :STL
基礎知識
容器
容器就是一些模板類的集合,不同之處就是容器中封裝的是資料結構
1、序列容器
主要有vector向量容器、list列表容器、deque雙端佇列容器
元素在容器中是無序的
2、排序容器
包括set容器,multiset多重集合容器、map對映容器、multimap多重對映容器
元素預設從小到大排序
3、雜湊容器
包括unordered_set雜湊集合、unirdered_multlist雜湊多重集合、unordered_map 雜湊對映以及 unordered_multimap 雜湊多重對映
元素是未排序的,元素位置由雜湊函式確定
迭代器
根據容器的型別大致分為:輸入迭代器、輸出迭代器、前向迭代器、雙向迭代器、隨機訪問迭代器
PS:輸入迭代器和輸出迭代器,不是把陣列和容器當做物件,而是把輸入流/輸出流作為操作物件
1、向前迭代器
假設 p 是一個前向迭代器,則 p 支援 ++p,p++,*p 操作,還可以被複制或賦值,可以用 == 和 != 運算子進行比較。
此外,兩個正向迭代器可以互相賦值。
2、雙向迭代器
雙向迭代器具有正向迭代器的全部功能,除此之外,假設 p 是一個雙向迭代器,則還可以進行 --p 或者 p-- 操作(即一次向後移動一個位置)。
3、隨機訪問迭代器
隨機訪問迭代器具有雙向迭代器的全部功能。除此之外,假設 p 是一個隨機訪問迭代器,i 是一個整型變數或常量,則 p 還支援以下操作:
- p+=i:使得 p 往後移動 i 個元素。
- p-=i:使得 p 往前移動 i 個元素。
- p+i:返回 p 後面第 i 個元素的迭代器。
- p-i:返回 p 前面第 i 個元素的迭代器。
- p[i]:返回 p 後面第 i 個元素的引用。
兩個隨機訪問迭代器 p1、p2 還可以用 <、>、<=、>= 運算子進行比較。另外,表示式 p2-p1 也是有定義的,其返回值表示 p2 所指向元素和 p1 所指向元素的序號之差(也可以說是 p2 和 p1 之間的元素個數減一)
不同容器的迭代器:
PS:容器介面卡 stack 和 queue 沒有迭代器,它們包含有一些成員函式,可以用來對元素進行訪問。
定義
四種定義方式:
通過定義以上幾種迭代器,就可以讀取它指向的元素,*迭代器名
- 對正向迭代器進行 ++ 操作時,迭代器會指向容器中的後一個元素;
- 而對反向迭代器進行 ++ 操作時,迭代器會指向容器中的前一個元素。
以上 4 種定義迭代器的方式,並不是每個容器都適用。有一部分容器同時支援以上 4 種方式,比如 array、deque、vector;而有些容器只支援其中部分的定義方式,例如 forward_list 容器只支援定義正向迭代器,不支援定義反向迭代器。
反向迭代器:
rbegin()指向最後一個元素,rend()指向第一個元素
begin()指向第一個元素,end()是指向最後一個元素的下一個
舉例:
先了解一下vector中的函式:
- push_back( ) 成員函式在向量的末尾插入值,如果有必要會擴充套件向量的大小。
- size( ) 函式顯示向量的大小。
- begin( ) 函式返回一個指向向量開頭的迭代器。
- end( ) 函式返回一個指向向量末尾的迭代器。
#include <iostream> //需要引入 vector 標頭檔案 #include <vector> using namespace std; int main() { vector<int> v; //v被初始化成有10個元素 for(int i=0;i<10;i++) { v.push_back(i); } cout << "第一種遍歷方法:" << endl; //size返回元素個數,像普通陣列一樣使用vector容器 for (int i = 0; i < v.size(); ++i) cout << v[i] <<" "; //建立一個正向迭代器,當然,vector也支援其他 3 種定義迭代器的方式 cout << endl << "第二種遍歷方法:" << endl; vector<int>::iterator i; //用 != 比較兩個迭代器 for (i = v.begin(); i != v.end(); ++i) cout << *i << " "; cout << endl << "第三種遍歷方法:" << endl; for (i = v.begin(); i < v.end(); ++i) //用 < 比較兩個迭代器 cout << *i << " "; cout << endl << "第四種遍歷方法:" << endl; i = v.begin(); while (i < v.end()) { //間隔一個輸出 cout << *i << " "; i += 2; // 隨機訪問迭代器支援 "+= 整數" 的操作 } }
轉載:如何能熟練掌握STL?
STL初識
STL誕生
- 長久以來,軟體界一直希望建立一種可重複利用的東西
- C++的面向物件和泛型程式設計思想,目的就是複用性的提升
- 大多情況下,資料結構和演算法都未能有一套標準,導致被迫從事大量重複工作
- 為了建立資料結構和演算法的一套標準,誕生了STL
STL基本概念
- STL(Standard Template Library,標準模板庫)
- STL 從廣義上分為: 容器(container)、 演算法(algorithm)、 迭代器(iterator)
- 容器和演算法之間通過迭代器進行無縫連線。
- STL 幾乎所有的程式碼都採用了模板類或者模板函式
STL六大元件
STL大體分為六大元件,分別是:容器、演算法、迭代器、仿函式、介面卡(配接器)、空間配置器
- 容器:各種資料結構,如vector、list、deque、set、map等,用來存放資料。
- 演算法:各種常用的演算法,如sort、find、copy、for_each等
- 迭代器:扮演了容器與演算法之間的膠合劑。
- 仿函式:行為類似函式,可作為演算法的某種策略。
- 介面卡:一種用來修飾容器或者仿函式或迭代器介面的東西。
- 空間配置器:負責空間的配置與管理
STL中容器、演算法和迭代器
1、容器:存放物品STL容器就是將運用最廣泛的一些資料結構實現出來
常用的資料結構:陣列, 連結串列,樹, 棧, 佇列, 集合, 對映表 等
這些容器分為序列式容器和關聯式容器兩種:
序列式容器:強調值的排序,序列式容器中的每個元素均有固定的位置。 關聯式容器: 二叉樹結構,各元素之間沒有嚴格的物理上的順序關係
2、演算法:解決問題的方法有限的步驟,解決邏輯或數學上的問題,這一門學科我們叫做演算法(Algorithms)
演算法分為: 質變演算法和非質變演算法。
質變演算法:是指運算過程中會更改區間內的元素的內容。例如拷貝,替換,刪除等等
非質變演算法:是指運算過程中不會更改區間內的元素內容,例如查詢、計數、遍歷、尋找極值等等
3、迭代器:連線容器和演算法的提供一種方法,使之能夠依序尋訪某個容器所含的各個元素,而又無需暴露該容器的內部表示方式。
每個容器都有自己專屬的迭代器
迭代器使用非常類似於指標,初學階段我們可以先理解迭代器為指標
迭代器種類:
常用的容器中的迭代器種類為雙向迭代器和隨機訪問迭代器
容器、演算法和迭代器初識
STL中最常用的容器為Vector,可以理解為陣列,下面我們將學習如何向這個容器中插入資料、並遍歷這個容器
1、vector存放內建資料容器: vector
演算法: for_each
迭代器: vector<int>::iterator
示例:
#include <vector> #include <algorithm> #include <iostream> using namespace std; void MyPrint(int val) { cout << val << endl; } void test01() { //建立vector容器物件,並且通過模板引數指定容器中存放的資料的型別 vector<int> v; //向容器中放資料 v.push_back(10); v.push_back(20); v.push_back(30); v.push_back(40); //每一個容器都有自己的迭代器,迭代器是用來遍歷容器中的元素 //v.begin()返回迭代器,這個迭代器指向容器中第一個資料 //v.end()返回迭代器,這個迭代器指向容器元素的最後一個元素的下一個位置 //vector<int>::iterator 拿到vector<int>這種容器的迭代器型別 vector<int>::iterator pBegin = v.begin(); vector<int>::iterator pEnd = v.end(); //第一種遍歷方式: while (pBegin != pEnd) { cout << *pBegin << endl; pBegin++; } cout << endl; //第二種遍歷方式: for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout << *it << endl; } cout << endl; //第三種遍歷方式: //使用STL提供標準遍歷演算法 標頭檔案 algorithm for_each(v.begin(), v.end(), MyPrint); } int main() { test01(); system("pause"); return 0; }2、vector存放自定義資料型別 需求:vector中存放自定義資料型別,並列印輸出 例如:
#include <iostream> #include <vector> #include <string> using namespace std; //自定義資料型別 class Person { public: Person(string name, int age) { mName = name; mAge = age; } public: string mName; int mAge; }; //存放物件 void test01() { vector<Person> v; //建立資料 Person p1("aaa", 10); Person p2("bbb", 20); Person p3("ccc", 30); Person p4("ddd", 40); Person p5("eee", 50); v.push_back(p1);//物件 v.push_back(p2); v.push_back(p3); v.push_back(p4); v.push_back(p5); for (vector<Person>::iterator it = v.begin(); it != v.end(); it++) { cout << "Name:" << (*it).mName << " Age:" << (*it).mAge << endl; } } //放物件指標 void test02() { vector<Person*> v; //建立資料 Person p1("aaa", 10); Person p2("bbb", 20); Person p3("ccc", 30); Person p4("ddd", 40); Person p5("eee", 50); v.push_back(&p1);//物件地址 v.push_back(&p2); v.push_back(&p3); v.push_back(&p4); v.push_back(&p5); for (vector<Person*>::iterator it = v.begin(); it != v.end(); it++) { Person * p = (*it); cout << "Name:" << p->mName << " Age:" << (*it)->mAge << endl; } } int main() { test01(); cout << endl; test02(); system("pause"); return 0; }
3、vector容器巢狀容器
需求: 容器中巢狀容器,將所有資料進行遍歷
#include <iostream> #include <vector> using namespace std; //容器巢狀容器 void test01() { vector< vector<int> > v; vector<int> v1; vector<int> v2; vector<int> v3; vector<int> v4; for (int i = 0; i < 4; i++) { v1.push_back(i + 1);//1,2,3,4 v2.push_back(i + 2);//2,3,4,5 v3.push_back(i + 3);//3,4,5,6 v4.push_back(i + 4);//4,5,6,7 } //將容器元素插入到vector v中 v.push_back(v1); v.push_back(v2); v.push_back(v3); v.push_back(v4); for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++) { for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++) { cout << *vit << " "; } cout << endl; } } int main() { test01(); system("pause"); return 0; }
STL常用容器
string容器
string基本概念
(1)本質
string是C++風格的字串,而string本質上是一個類
(2)string和char *的區別:
- char * 是一個指標
- string是一個類,類內部封裝了char*,管理這個字串,是一個char*型的容器
(3)特點
string 類內部封裝了很多成員方法
例如:查詢find,拷貝copy,刪除delete, 替換replace,插入insert
string管理char*所分配的記憶體,不用擔心複製越界和取值越界等,由類內部進行負責
string建構函式
建構函式原型:
-
string();
//建立一個空的字串 例如: string str; -
string(const char* s);
//使用字串s初始化 -
string(const string& str);
//使用一個string物件初始化另一個string物件 -
string(int n, char c);
//使用n個字元c初始化
#include <string> #include <iostream> using namespace std; //string構造 void test01() { string s1; //建立空字串,呼叫無參建構函式 cout << "str1 = " << s1 << endl; const char* str = "hello world"; string s2(str); //把char* 轉換成了string cout << "str2 = " << s2 << endl; string s3(s2); //呼叫拷貝建構函式,string物件初始化string cout << "str3 = " << s3 << endl; string s4(10, 'a'); cout << "str4 = " << s4 << endl; } int main() { test01(); system("pause"); return 0; }
string的多種構造方式沒有可比性,靈活使用即可!
string賦值操作
功能描述:
- 給string字串進行賦值
賦值的函式原型:
-
string& operator=(const char* s);
//char*型別字串 賦值給當前的字串 -
string& operator=(const string &s);
//把字串s賦給當前的字串 -
string& operator=(char c);
//字元賦值給當前的字串 -
string& assign(const char *s, int n);
//把字串s的前n個字元賦給當前的字串 -
string& assign(int n, char c);
//用n個字元c賦給當前字串
舉例:
#include <string> #include <iostream> using namespace std; //賦值 void test01() { string str1; str1 = "hello world"; cout << "str1 = " << str1 << endl; string str2; str2 = str1; cout << "str2 = " << str2 << endl; string str3; str3 = 'a'; cout << "str3 = " << str3 << endl; string str4; str4.assign("hello c++"); cout << "str4 = " << str4 << endl; string str5; str5.assign("hello c++",5); cout << "str5 = " << str5 << endl; string str6; str6.assign(str5); cout << "str6 = " << str6 << endl; string str7; str7.assign(5, 'x'); cout << "str7 = " << str7 << endl; } int main() { test01(); system("pause"); return 0; }
說明:string賦值方式很多,operator=最常用
string字串拼接
功能描述:
- 實現在字串末尾拼接字串
函式原型:
-
string& operator+=(const char* str);
//過載+=操作符 -
string& operator+=(const char c);
//過載+=操作符 -
string& operator+=(const string& str);
//過載+=操作符 -
string& append(const char *s);
//把字串s連線到當前字串結尾 -
string& append(const char *s, int n);
//把字串s的前n個字元連線到當前字串結尾 -
string& append(const string &s);
//同operator+=(const string& str) -
string& append(const string &s, int pos, int n);
//字串s中從pos開始的n個字元連線到字串結尾
#include <string> #include <iostream> using namespace std; //字串拼接 void test01() { string str1 = "我"; str1 += "愛玩遊戲"; cout << "str1 = " << str1 << endl; str1 += ':'; cout << "str1 = " << str1 << endl; string str2 = "LOL DNF"; str1 += str2; cout << "str1 = " << str1 << endl; string str3 = "I"; str3.append(" love "); str3.append("game abcde", 4); //str3.append(str2); str3.append(str2, 4, 3); // 從下標4位置開始 ,擷取3個字元,拼接到字串末尾 cout << "str3 = " << str3 << endl; } int main() { test01(); system("pause"); return 0; }
string查詢和替換
功能描述:
- 查詢:查詢指定字串是否存在
- 替換:在指定的位置替換字串
函式原型:
-
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;
//從pos位置查詢s的前n個字元第一次位置 -
int find(const char c, int pos = 0) const;
//查詢字元c第一次出現位置 -
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;
//從pos查詢s的前n個字元最後一次位置 -
int rfind(const char c, int pos = 0) const;
//查詢字元c最後一次出現位置 -
string& replace(int pos, int n, const string& str);
//替換從pos開始n個字元為字串str -
string& replace(int pos, int n,const char* s);
//替換從pos開始的n個字元為字串s
#include <string> #include <iostream> using namespace std; //查詢和替換 void test01() { //查詢 string str1 = "abcdefgde"; int pos = str1.find("de"); if (pos == -1) { cout << "未找到" << endl; } else { cout << "pos = " << pos << endl; } pos = str1.rfind("de"); cout << "pos = " << pos << endl; } void test02() { //替換 string str1 = "abcdefgde"; str1.replace(1, 3, "1111"); cout << "str1 = " << str1 << endl; } int main() { test01(); test02(); system("pause"); return 0; }
總結:
- find查詢是從左往後,rfind從右往左
- find找到字串後返回查詢的第一個字元位置,找不到返回-1
- replace在替換時,要指定從哪個位置起,多少個字元,替換成什麼樣的字串
string字串比較
功能描述:
- 字串之間的比較
比較方式:
- 字串比較是按字元的ASCII碼進行對比
= 返回 0
> 返回 1
< 返回 -1
函式原型:
-
int compare(const string &s) const;
//與字串s比較 -
int compare(const char *s) const;
//與字串s比較
舉例:
#include <string> #include <iostream> using namespace std; //字串比較 void test01() { string s1 = "hello"; string s2 = "aello"; int ret = s1.compare(s2); if (ret == 0) { cout << "s1 = s2" << endl; } else if (ret > 0) { cout << "s1 > s2" << endl; } else { cout << "s1 < s2" << endl; } } int main() { test01(); system("pause"); return 0; }
總結:字串對比主要是用於比較兩個字串是否相等,判斷誰大誰小的意義並不是很大
string字元存取
string中單個字元存取方式有兩種
-
char& operator[](int n);
//通過[]方式取字元 -
char& at(int n);
//通過at方法獲取字元
舉例:
#include <string> #include <iostream> using namespace std; void test01() { string str = "hello world"; for (int i = 0; i < str.size(); i++) { cout << str[i] << " "; } cout << endl; for (int i = 0; i < str.size(); i++) { cout << str.at(i) << " "; } cout << endl; //字元修改 str[0] = 'x'; str.at(1) = 'x'; cout << str << endl; } int main() { test01(); system("pause"); return 0; }
string插入和刪除
功能描述:
- 對string字串進行插入和刪除字元操作
函式原型:
-
string& insert(int pos, const char* s);
//在post處插入字串 -
string& insert(int pos, const string& str);
//在post處插入字串 -
string& insert(int pos, int n, char c);
//在在post處插入n個字元c -
string& erase(int pos, int n = npos);
//刪除從Pos開始的n個字元
#include <string> #include <iostream> using namespace std; //字串插入和刪除 void test01() { string str = "hello"; str.insert(1, "111"); cout << str << endl; str.erase(1, 3); //從1號位置開始3個字元 cout << str << endl; } int main() { test01(); system("pause"); return 0; }
總結:插入和刪除的起始下標都是從0開始
string子串
功能描述:
- 從字串中獲取想要的子串
函式原型:
-
string substr(int pos = 0, int n = npos) const;
//返回由pos開始的n個字元組成的字串
舉例:
#include <string> #include <iostream> using namespace std; //子串 void test01() { string str = "abcdefg"; string subStr = str.substr(1, 3); cout << "subStr = " << subStr << endl; string email = "[email protected]"; int pos = email.find("@"); string username = email.substr(0, pos); cout << "username: " << username << endl; } int main() { test01(); system("pause"); return 0; }
vector容器
vector基本概念
功能:
- vector資料結構和陣列非常相似,也稱為單端陣列
vector與普通陣列區別:
- 不同之處在於陣列是靜態空間,而vector可以動態擴充套件
動態擴充套件:
- 並不是在原空間之後續接新空間,而是找更大的記憶體空間,然後將原資料拷貝新空間,釋放原空間
- vector容器的迭代器是支援隨機訪問的迭代器
vector建構函式
功能描述:
- 建立vector容器
函式原型:
-
vector<T> v;
//採用模板實現類實現,預設建構函式 -
vector(v.begin(), v.end());
//將v[begin(), end())區間中的元素拷貝給本身。 -
vector(n, elem);
//建構函式將n個elem拷貝給本身。 -
vector(const vector &vec);
//拷貝建構函式。
#include <iostream> #include <vector> using namespace std; void printVector(vector<int>& v) { for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; } void test01() { vector<int> v1; //無參構造 for (int i = 0; i < 10; i++) { v1.push_back(i); } printVector(v1); vector<int> v2(v1.begin(), v1.end());//將v1的元素從頭到尾拷貝給v2 printVector(v2); vector<int> v3(10, 100); printVector(v3); vector<int> v4(v3); printVector(v4); } int main() { test01(); system("pause"); return 0; }
vector的賦值操作
功能描述:
- 給vector容器進行賦值
函式原型:
-
vector& operator=(const vector &vec);
//過載等號操作符 -
assign(beg, end);
//將[beg, end)區間中的資料拷貝賦值給本身。 -
assign(n, elem);
//將n個elem拷貝賦值給本身。
#include <iostream> #include <vector> using namespace std; void printVector(vector<int>& v) { for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; } //賦值操作 void test01() { vector<int> v1; //無參構造 for (int i = 0; i < 10; i++) { v1.push_back(i); } printVector(v1); vector<int>v2; v2 = v1; printVector(v2); vector<int>v3; v3.assign(v1.begin(), v1.end()); printVector(v3); vector<int>v4; v4.assign(10, 100); printVector(v4); } int main() { test01(); system("pause"); return 0; }
總結:vector賦值方式比較簡單,使用operator=,或者assign都可以
vector容量和大小
功能描述:
- 對vector容器的容量和大小操作
函式原型:
-
empty();
//判斷容器是否為空 -
capacity();
//容器的容量,即容器的資料型別(大小) -
size();
//返回容器中元素的個數 -
resize(int num);
//重新指定容器的長度為num,若容器變長,則以預設值填充新位置。//如果容器變短,則末尾超出容器長度的元素被刪除。
-
resize(int num, elem);
//重新指定容器的長度為num,若容器變長,則以elem值填充新位置。 //如果容器變短,則末尾超出容器長度的元素被刪除
#include <iostream> #include <vector> using namespace std; void printVector(vector<int>& v) { for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; } void test01() { vector<int> v1; for (int i = 0; i < 10; i++) { v1.push_back(i); } printVector(v1); if (v1.empty()) { cout << "v1為空" << endl; } else { cout << "v1不為空" << endl; cout << "v1的容量 = " << v1.capacity() << endl; cout << "v1的大小 = " << v1.size() << endl; } //resize 重新指定大小 ,若指定的更大,預設用0填充新位置,可以利用過載版本替換預設填充 v1.resize(15,10); printVector(v1); //resize 重新指定大小 ,若指定的更小,超出部分元素被刪除 v1.resize(5); printVector(v1); } int main() { test01(); system("pause"); return 0; }
vector插入和刪除
功能描述:
- 對vector容器進行插入、刪除操作
函式原型:
-
push_back(ele);
//尾部插入元素ele -
pop_back();
//刪除最後一個元素 -
insert(const_iterator pos, ele);
//迭代器指向位置pos插入元素ele -
insert(const_iterator pos, int count,ele);
//迭代器指向位置pos插入count個元素ele -
erase(const_iterator pos);
//刪除迭代器指向的元素 -
erase(const_iterator start, const_iterator end);
//刪除迭代器從start到end之間的元素 -
clear();
//刪除容器中所有元素
#include <iostream> #include <vector> using namespace std; void printVector(vector<int>& v) { for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; } //插入和刪除 void test01() { vector<int> v1; //尾插 v1.push_back(10); v1.push_back(20); v1.push_back(30); v1.push_back(40); v1.push_back(50); printVector(v1); //尾刪 v1.pop_back(); printVector(v1); //插入 v1.insert(v1.begin(), 100); printVector(v1); v1.insert(v1.begin(), 2, 1000); printVector(v1); //刪除 v1.erase(v1.begin()); printVector(v1); //清空 v1.erase(v1.begin(), v1.end()); v1.clear(); printVector(v1); } int main() { test01(); system("pause"); return 0; }
vector資料存取
功能描述:
- 對vector中的資料的存取操作
函式原型:
-
at(int idx);
//返回索引 idx 所指的資料 -
operator[];
//返回索引idx所指的資料 -
front();
//返回容器中第一個資料元素 -
back();
//返回容器中最後一個數據元素
舉例:
#include <iostream> #include <vector> using namespace std; void test01() { vector<int>v1; for (int i = 0; i < 10; i++) { v1.push_back(i); } for (int i = 0; i < v1.size(); i++) { cout << v1[i] << " "; } cout << endl; for (int i = 0; i < v1.size(); i++) { cout << v1.at(i) << " "; } cout << endl; cout << "v1的第一個元素為: " << v1.front() << endl; cout << "v1的最後一個元素為: " << v1.back() << endl; } int main() { test01(); system("pause"); return 0; }
vector互換容器
功能描述:
- 實現兩個容器內元素進行互換
函式原型:
-
swap(vec);
// 將vec與本身的元素互換
舉例:
#include <iostream> #include <vector> using namespace std; void printVector(vector<int>& v) { for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; } void test01() { vector<int>v1; for (int i = 0; i < 10; i++) { v1.push_back(i); } printVector(v1); vector<int>v2; for (int i = 10; i > 0; i--) { v2.push_back(i); } printVector(v2); //互換容器 cout << "互換後" << endl; v1.swap(v2); printVector(v1); printVector(v2); } void test02() { vector<int> v; for (int i = 0; i < 100000; i++) { v.push_back(i); } cout << "v的容量為:" << v.capacity() << endl; cout << "v的大小為:" << v.size() << endl; v.resize(3); cout << "v的容量為:" << v.capacity() << endl; cout << "v的大小為:" << v.size() << endl; //收縮記憶體 vector<int>(v).swap(v); //匿名物件 cout << "v的容量為:" << v.capacity() << endl; cout << "v的大小為:" << v.size() << endl; } int main() { test01(); test02(); system("pause"); return 0; }
vector預留空間
功能描述:
- 減少vector在動態擴充套件容量時的擴充套件次數
函式原型:
-
reserve(int len);
//容器預留len個元素長度,預留位置不初始化,元素不可訪問。
舉例:
#include <iostream> #include <vector> using namespace std; void test01() { vector<int> v; //預留空間 v.reserve(100000); int num = 0; int* p = NULL; for (int i = 0; i < 100000; i++) { v.push_back(i); if (p != &v[0]) { p = &v[0]; num++; } } cout << "num:" << num << endl; } int main() { test01(); system("pause"); return 0; }
說明:如果資料量較大,可以一開始利用reserve預留空間
deque容器
deque容器基本概念
功能:
- 雙端陣列,可以對頭端進行插入刪除操作
deque與vector區別:
- vector對於頭部的插入刪除效率低,資料量越大,效率越低
- deque相對而言,對頭部的插入刪除速度回比vector快
- vector訪問元素時的速度會比deque快,這和兩者內部實現有關
deque內部工作原理:
- deque內部有個中控器,維護每段緩衝區中的內容,緩衝區中存放真實資料
- 中控器維護的是每個緩衝區的地址,使得使用deque時像一片連續的記憶體空間
- deque容器的迭代器也是支援隨機訪問的
deque建構函式
功能描述:
- deque容器構造
函式原型:
-
deque<T>
deqT; //預設構造形式 -
deque(beg, end);
//建構函式將[beg, end)區間中的元素拷貝給本身。 -
deque(n, elem);
//建構函式將n個elem拷貝給本身。 -
deque(const deque &deq);
//拷貝建構函式
#include <iostream> #include <deque> using namespace std; void printDeque(const deque<int>& d) { for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) { cout << *it << " "; } cout << endl; } //deque構造 void test01() { deque<int> d1; //無參建構函式 for (int i = 0; i < 10; i++) { d1.push_back(i); } printDeque(d1); deque<int> d2(d1.begin(),d1.end()); printDeque(d2); deque<int>d3(10,100); printDeque(d3); deque<int>d4 = d3; printDeque(d4); } int main() { test01(); system("pause"); return 0; }
deque賦值操作
功能描述:
- 給deque容器進行賦值
函式原型:
-
deque& operator=(const deque &deq);
//過載等號操作符 -
assign(beg, end);
//將[beg, end)區間中的資料拷貝賦值給本身。 -
assign(n, elem);
//將n個elem拷貝賦值給本身。
舉例:
#include <iostream> #include <deque> using namespace std; void printDeque(const deque<int>& d) { for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) { cout << *it << " "; } cout << endl; } //賦值操作 void test01() { deque<int> d1; for (int i = 0; i < 10; i++) { d1.push_back(i); } printDeque(d1); deque<int>d2; d2 = d1; printDeque(d2); deque<int>d3; d3.assign(d1.begin(), d1.end()); printDeque(d3); deque<int>d4; d4.assign(10, 100); printDeque(d4); } int main() { test01(); system("pause"); return 0; }
deque大小操作
功能描述:
- 對deque容器的大小進行操作
函式原型:
-
deque.empty();
//判斷容器是否為空 -
deque.size();
//返回容器中元素的個數 -
deque.resize(num);
//重新指定容器的長度為num,若容器變長,則以預設值填充新位置。 //如果容器變短,則末尾超出容器長度的元素被刪除。
-
deque.resize(num, elem);
//重新指定容器的長度為num,若容器變長,則以elem值填充新位置。//如果容器變短,則末尾超出容器長度的元素被刪除。
#include <iostream> #include <deque> using namespace std; void printDeque(const deque<int>& d) { for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) { cout << *it << " "; } cout << endl; } //大小操作 void test01() { deque<int> d1; for (int i = 0; i < 10; i++) { d1.push_back(i); } printDeque(d1); //判斷容器是否為空 if (d1.empty()) { cout << "d1為空!" << endl; } else { cout << "d1不為空!" << endl; //統計大小 cout << "d1的大小為:" << d1.size() << endl; } //重新指定大小 d1.resize(15, 1); printDeque(d1); d1.resize(5); printDeque(d1); } int main() { test01(); system("pause"); return 0; }
說明:deque沒有容量的概念
deque 插入和刪除
功能描述:
- 向deque容器中插入和刪除資料
函式原型:
兩端插入操作:
-
push_back(elem);
//在容器尾部新增一個數據 -
push_front(elem);
//在容器頭部插入一個數據 -
pop_back();
//刪除容器最後一個數據 -
pop_front();
//刪除容器第一個資料
指定位置操作:
-
insert(pos,elem);
//在pos位置插入一個elem元素的拷貝,返回新資料的位置。 -
insert(pos,n,elem);
//在pos位置插入n個elem資料,無返回值。 -
insert(pos,beg,end);
//在pos位置插入[beg,end)區間的資料,無返回值。 -
clear();
//清空容器的所有資料 -
erase(beg,end);
//刪除[beg,end)區間的資料,返回下一個資料的位置。 -
erase(pos);
//刪除pos位置的資料,返回下一個資料的位置。
#include <iostream> #include <deque> using namespace std; void printDeque(const deque<int>& d) { for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) { cout << *it << " "; } cout << endl; } //兩端操作 void test01() { deque<int> d; //尾插 d.push_back(10); d.push_back(20); //頭插 d.push_front(100); d.push_front(200); printDeque(d); //尾刪 d.pop_back(); //頭刪 d.pop_front(); printDeque(d); } //插入 void test02() { deque<int> d; d.push_back(10); d.push_back(20); d.push_front(100); d.push_front(200); printDeque(d); d.insert(d.begin(), 1000); printDeque(d); d.insert(d.begin(), 2,10000); printDeque(d); deque<int>d2; d2.push_back(1); d2.push_back(2); d2.push_back(3); d.insert(d.begin(), d2.begin(), d2.end()); printDeque(d); } //刪除 void test03() { deque<int> d; d.push_back(10); d.push_back(20); d.push_front(100); d.push_front(200); printDeque(d); d.erase(d.begin()); printDeque(d); d.erase(d.begin(), d.end()); d.clear(); printDeque(d); } int main() { test01(); test02(); test03(); system("pause"); return 0; }
說明:插入和刪除提供的位置是迭代器!
deque 資料存取
功能描述:
- 對deque 中的資料的存取操作
函式原型:
-
at(int idx);
//返回索引idx所指的資料 -
operator[];
//返回索引idx所指的資料 -
front();
//返回容器中第一個資料元素 -
back();
//返回容器中最後一個數據元素
舉例:
#include <iostream> #include <deque> using namespace std; void printDeque(const deque<int>& d) { for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) { cout << *it << " "; } cout << endl; } //資料存取 void test01() { deque<int> d; d.push_back(10); d.push_back(20); d.push_front(100); d.push_front(200); for (int i = 0; i < d.size(); i++) { cout << d[i] << " "; } cout << endl; for (int i = 0; i < d.size(); i++) { cout << d.at(i) << " "; } cout << endl; cout << "front:" << d.front() << endl; cout << "back:" << d.back() << endl; } int main() { test01(); system("pause"); return 0; }
說明:除了用迭代器獲取deque容器中元素,[ ]和at也可以
deque 排序
功能描述:
- 利用演算法實現對deque容器進行排序
演算法:
-
sort(iterator beg, iterator end)
//對beg和end區間內元素進行排序
舉例:
#include <iostream> #include <deque> #include <algorithm> using namespace std; void printDeque(const deque<int>& d) { for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) { cout << *it << " "; } cout << endl; } void test01() { deque<int> d; d.push_back(10); d.push_back(20); d.push_front(100); d.push_front(200); printDeque(d); sort(d.begin(), d.end()); printDeque(d); } int main() { test01(); system("pause"); return 0; }
說明:sort演算法非常實用,使用時包含標頭檔案 algorithm即可
案例-評委打分
案例描述:
有5名選手:選手ABCDE,10個評委分別對每一名選手打分,去除最高分,去除評委中最低分,取平均分。
實現步驟:
- 建立五名選手,放到vector中
- 遍歷vector容器,取出來每一個選手,執行for迴圈,可以把10個評分打分存到deque容器中
- sort演算法對deque容器中分數排序,去除最高和最低分
- deque容器遍歷一遍,累加總分
- 獲取平均分
#include <iostream> #include <deque> #include <vector> #include <algorithm> #include <ctime> using namespace std; //選手類 class Person { public: Person(string name, int score) { this->m_Name = name; this->m_Score = score; } string m_Name; //姓名 int m_Score; //平均分 }; void createPerson(vector<Person>&v) { string nameSeed = "ABCDE"; for (int i = 0; i < 5; i++) { string name = "選手"; name += nameSeed[i]; int score = 0; Person p(name, score); //將建立的person物件 放入到容器中 v.push_back(p); } } //打分 void setScore(vector<Person>&v) { for (vector<Person>::iterator it = v.begin(); it != v.end(); it++) { //將評委的分數 放入到deque容器中 deque<int>d; for (int i = 0; i < 10; i++) { int score = rand() % 41 + 60; // 60 ~ 100 d.push_back(score); } //cout << "選手: " << it->m_Name << " 打分: " << endl; //for (deque<int>::iterator dit = d.begin(); dit != d.end(); dit++) //{ // cout << *dit << " "; //} //cout << endl; //排序 sort(d.begin(), d.end()); //去除最高和最低分 d.pop_back(); d.pop_front(); //取平均分 int sum = 0; for (deque<int>::iterator dit = d.begin(); dit != d.end(); dit++) { sum += *dit; //累加每個評委的分數 } int avg = sum / d.size(); //將平均分 賦值給選手身上 it->m_Score = avg; } } void showScore(vector<Person>&v) { for (vector<Person>::iterator it = v.begin(); it != v.end(); it++) { cout << "姓名: " << it->m_Name << " 平均分: " << it->m_Score << endl; } } int main() { //隨機數種子 srand((unsigned int)time(NULL)); //1、建立5名選手 vector<Person>v; //存放選手容器 createPerson(v); //測試 //for (vector<Person>::iterator it = v.begin(); it != v.end(); it++) //{ // cout << "姓名: " << (*it).m_Name << " 分數: " << (*it).m_Score << endl; //} //2、給5名選手打分 setScore(v); //3、顯示最後得分 showScore(v); system("pause"); return 0; }
說明: 選取不同的容器操作資料,可以提升程式碼的效率
stack容器
stack 基本概念
概念:stack是一種先進後出(First In Last Out,FILO)的資料結構,它只有一個出口
棧中只有頂端的元素才可以被外界使用,因此棧不允許有遍歷行為
棧中進入資料稱為 --- 入棧 push
棧中彈出資料稱為 --- 出棧 pop
生活中的棧:
stack 常用介面
功能描述:棧容器常用的對外介面
建構函式:
-
stack<T> stk;
//stack採用模板類實現, stack物件的預設構造形式 -
stack(const stack &stk);
//拷貝建構函式
賦值操作:
-
stack& operator=(const stack &stk);
//過載等號操作符
資料存取:
-
push(elem);
//向棧頂新增元素 -
pop();
//從棧頂移除第一個元素 -
top();
//返回棧頂元素
大小操作:
-
empty();
//判斷堆疊是否為空 -
size();
//返回棧的大小
#include <iostream> #include <stack> using namespace std; //棧容器常用介面 void test01() { //建立棧容器 棧容器必須符合先進後出 stack<int> s; //向棧中新增元素,叫做 壓棧 入棧 s.push(10); s.push(20); s.push(30); while (!s.empty()) { //輸出棧頂元素 cout << "棧頂元素為: " << s.top() << endl; //彈出棧頂元素 s.pop(); cout << "棧的大小為:" << s.size() << endl; } } int main() { test01(); system("pause"); return 0; }
queue容器
queue 基本概念
概念:Queue是一種先進先出(First In First Out,FIFO)的資料結構,它有兩個出口
佇列容器允許從一端新增元素,從另一端移除元素
佇列中只有隊頭和隊尾才可以被外界使用,因此佇列不允許有遍歷行為
佇列中進資料稱為 --- 入隊 push
佇列中出資料稱為 --- 出隊 pop
生活中的佇列:
queue 常用介面
功能描述:棧容器常用的對外介面
建構函式:
-
queue<T> que;
//queue採用模板類實現,queue物件的預設構造形式 -
queue(const queue &que);
//拷貝建構函式
賦值操作:
-
queue& operator=(const queue &que);
//過載等號操作符
資料存取:
-
push(elem);
//往隊尾新增元素 -
pop();
//從隊頭移除第一個元素 -
back();
//返回最後一個元素 -
front();
//返回第一個元素
大小操作:
-
empty();
//判斷堆疊是否為空 -
size();
//返回棧的大小
#include <iostream> #include <queue> #include <string> using namespace std; class Person { public: Person(string name, int age) { this->m_Name = name; this->m_Age = age; } string m_Name; int m_Age; }; void test01() { //建立佇列 queue<Person> q; //準備資料 Person p1("唐僧", 30); Person p2("孫悟空", 1000); Person p3("豬八戒", 900); Person p4("沙僧", 800); //向佇列中新增元素 入隊操作 q.push(p1); q.push(p2); q.push(p3); q.push(p4); //佇列不提供迭代器,更不支援隨機訪問 while (!q.empty()) { //輸出隊頭元素 cout << "隊頭元素-- 姓名: " << q.front().m_Name << " 年齡: "<< q.front().m_Age << endl; cout << "隊尾元素-- 姓名: " << q.back().m_Name << " 年齡: " << q.back().m_Age << endl; cout << endl; //彈出隊頭元素 q.pop(); } cout << "佇列大小為:" << q.size() << endl; } int main() { test01(); system("pause"); return 0; }
list容器
list基本概念
功能:將資料進行鏈式儲存
連結串列(list)是一種物理儲存單元上非連續的儲存結構,資料元素的邏輯順序是通過連結串列中的指標連結實現的
連結串列的組成:連結串列由一系列結點組成
結點的組成:一個是儲存資料元素的資料域,另一個是儲存下一個結點地址的指標域
STL中的連結串列是一個雙向迴圈連結串列
由於連結串列的儲存方式並不是連續的記憶體空間,因此連結串列list中的迭代器只支援前移和後移,屬於雙向迭代器
list的優點:
- 採用動態儲存分配,不會造成記憶體浪費和溢位
- 連結串列執行插入和刪除操作十分方便,修改指標即可,不需要移動大量元素
list的缺點:
- 連結串列靈活,但是空間(指標域) 和 時間(遍歷)額外耗費較大
List有一個重要的性質,插入操作和刪除操作都不會造成原有list迭代器的失效,這在vector是不成立的。
總結:STL中List和vector是兩個最常被使用的容器,各有優缺點
list建構函式
功能描述:
- 建立list容器
函式原型:
-
list<T> lst;
//list採用採用模板類實現,物件的預設構造形式: -
list(beg,end);
//建構函式將[beg, end)區間中的元素拷貝給本身。 -
list(n,elem);
//建構函式將n個elem拷貝給本身。 -
list(const list &lst);
//拷貝建構函式。
#include <iostream> #include <list> #include <string> using namespace std; void printList(const list<int>& L) { for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) { cout << *it << " "; } cout << endl; } void test01() { list<int>L1; L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40); printList(L1); list<int>L2(L1.begin(),L1.end()); printList(L2); list<int>L3(L2); printList(L3); list<int>L4(10, 1000); printList(L4); } int main() { test01(); system("pause"); return 0; }
list 賦值和交換
功能描述:
- 給list容器進行賦值,以及交換list容器
函式原型:
-
assign(beg, end);
//將[beg, end)區間中的資料拷貝賦值給本身。 -
assign(n, elem);
//將n個elem拷貝賦值給本身。 -
list& operator=(const list &lst);
//過載等號操作符 -
swap(lst);
//將lst與本身的元素互換。
#include <iostream> #include <list> #include <string> using namespace std; void printList(const list<int>& L) { for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) { cout << *it << " "; } cout << endl; } //賦值和交換 void test01() { list<int>L1; L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40); printList(L1); //賦值 list<int>L2; L2 = L1; printList(L2); list<int>L3; L3.assign(L2.begin(), L2.end()); printList(L3); list<int>L4; L4.assign(10, 100); printList(L4); } //交換 void test02() { list<int>L1; L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40); list<int>L2; L2.assign(10, 100); cout << "交換前: " << endl; printList(L1); printList(L2); cout << endl; L1.swap(L2); cout << "交換後: " << endl; printList(L1); printList(L2); } int main() { test01(); test02(); system("pause"); return 0; }
list 大小操作
功能描述:
- 對list容器的大小進行操作
函式原型:
-
size();
//返回容器中元素的個數 -
empty();
//判斷容器是否為空 -
resize(num);
//重新指定容器的長度為num,若容器變長,則以預設值填充新位置。
//如果容器變短,則末尾超出容器長度的元素被刪除。
-
resize(num, elem);
//重新指定容器的長度為num,若容器變長,則以elem值填充新位置。 //如果容器變短,則末尾超出容器長度的元素被刪除。
#include <iostream> #include <list> #include <string> using namespace std; void printList(const list<int>& L) { for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) { cout << *it << " "; } cout << endl; } //大小操作 void test01() { list<int>L1; L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40); printList(L1); if (L1.empty()) { cout << "L1為空" << endl; } else { cout << "L1不為空" << endl; cout << "L1的大小為: " << L1.size() << endl; } //重新指定大小 L1.resize(10); printList(L1); L1.resize(2); printList(L1); } int main() { test01(); system("pause"); return 0; }
list 插入和刪除
功能描述:
- 對list容器進行資料的插入和刪除
函式原型:
- push_back(elem);//在容器尾部加入一個元素
- pop_back();//刪除容器中最後一個元素
- push_front(elem);//在容器開頭插入一個元素
- pop_front();//從容器開頭移除第一個元素
- insert(pos,elem);//在pos位置插elem元素的拷貝,返回新資料的位置。
- insert(pos,n,elem);//在pos位置插入n個elem資料,無返回值。
- insert(pos,beg,end);//在pos位置插入[beg,end)區間的資料,無返回值。
- clear();//移除容器的所有資料
- erase(beg,end);//刪除[beg,end)區間的資料,返回下一個資料的位置。
- erase(pos);//刪除pos位置的資料,返回下一個資料的位置。
- remove(elem);//刪除容器中所有與elem值匹配的元素。
#include <iostream> #include <list> #include <string> using namespace std; void printList(const list<int>& L) { for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) { cout << *it << " "; } cout << endl; } //插入和刪除 void test01() { list<int> L; //尾插 L.push_back(10); L.push_back(20); L.push_back(30); //頭插 L.push_front(100); L.push_front(200); L.push_front(300); printList(L); //尾刪 L.pop_back(); printList(L); //頭刪 L.pop_front(); printList(L); //插入 list<int>::iterator it = L.begin(); L.insert(++it, 1000); printList(L); //刪除 it = L.begin(); L.erase(++it); printList(L); //移除 L.push_back(10000); L.push_back(10000); L.push_back(10000); printList(L); L.remove(10000); printList(L); //清空 L.clear(); printList(L); } int main() { test01(); system("pause"); return 0; }
list 資料存取
功能描述:
- 對list容器中資料進行存取
函式原型:
-
front();
//返回第一個元素。 -
back();
//返回最後一個元素。
舉例:
#include <iostream> #include <list> #include <string> using namespace std; //資料存取 void test01() { list<int>L1; L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40); //cout << L1.at(0) << endl;//錯誤 不支援at訪問資料 //cout << L1[0] << endl; //錯誤 不支援[]方式訪問資料 cout << "第一個元素為: " << L1.front() << endl; cout << "最後一個元素為: " << L1.back() << endl; //list容器的迭代器是雙向迭代器,不支援隨機訪問 list<int>::iterator it = L1.begin(); //it = it + 1;//錯誤,不可以跳躍訪問,即使是+1 } int main() { test01(); system("pause"); return 0; }
說明:list容器中不可以通過[]或者at方式訪問資料
list容器的迭代器是雙向迭代器,不支援隨機訪問
list 反轉和排序
功能描述:
- 將容器中的元素反轉,以及將容器中的資料進行排序
函式原型:
-
reverse();
//反轉連結串列 -
sort();
//連結串列排序(正序,預設為);sort(自定義排序函式)(反序)
#include <iostream> #include <list> #include <string> using namespace std; void printList(const list<int>& L) { for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) { cout << *it << " "; } cout << endl; } bool myCompare(int val1 , int val2) { return val1 > val2; } //反轉和排序 void test01() { list<int> L; L.push_back(90); L.push_back(30); L.push_back(20); L.push_back(70); printList(L); //反轉容器的元素 L.reverse(); printList(L); //排序 L.sort(); //預設的排序規則 從小到大 printList(L); L.sort(myCompare); //指定規則,從大到小 printList(L); } int main() { test01(); system("pause"); return 0; }
排序案例
案例描述:將Person自定義資料型別進行排序,Person中屬性有姓名、年齡、身高
排序規則:按照年齡進行升序,如果年齡相同按照身高進行降序
程式碼:
#include <iostream> #include <list> #include <string> using namespace std; class Person { public: Person(string name, int age , int height) { m_Name = name; m_Age = age; m_Height = height; } public: string m_Name; //姓名 int m_Age; //年齡 int m_Height; //身高 }; bool ComparePerson(Person& p1, Person& p2) { //12 10 //12 9 if (p1.m_Age == p2.m_Age) { return p1.m_Height > p2.m_Height;//降序,為0 } //5 10 //12 9 else { return p1.m_Age < p2.m_Age;//升序,為1 } } void test01() { list<Person> L; Person p1("劉備", 35 , 175); Person p2("曹操", 45 , 180); Person p3("孫權", 40 , 170); Person p4("趙雲", 25 , 190); Person p5("張飛", 35 , 160); Person p6("關羽", 35 , 200); L.push_back(p1); L.push_back(p2); L.push_back(p3); L.push_back(p4); L.push_back(p5); L.push_back(p6); for (list<Person>::iterator it = L.begin(); it != L.end(); it++) { cout << "姓名: " << it->m_Name << " 年齡: " << it->m_Age << " 身高: " << it->m_Height << endl; } cout << "-------------排序後-----------------" << endl; L.sort(ComparePerson); //排序 for (list<Person>::iterator it = L.begin(); it != L.end(); it++) { cout << "姓名: " << it->m_Name << " 年齡: " << it->m_Age << " 身高: " << it->m_Height << endl; } } int main() { test01(); system("pause"); return 0; }
說明:
- 對於自定義資料型別,必須要指定排序規則,否則編譯器不知道如何進行排序
- 高階排序只是在排序規則上再進行一次邏輯規則制定,並不複雜
set/multiset容器
set基本概念
簡介:
- 所有元素都會在插入時自動被排序
本質:
- set/multiset屬於關聯式容器,底層結構是用二叉樹實現。
set和multiset區別:
- set不允許容器中有重複的元素
- multiset允許容器中有重複的元素
set構造和賦值
功能描述:建立set容器以及賦值
構造:
-
set<T> st;
//預設建構函式: -
set(const set &st);
//拷貝建構函式
賦值:
-
set& operator=(const set &st);
//過載等號操作符
程式碼:
#include <iostream> #include <set> #include <string> using namespace std; void printSet(set<int> & s) { for (set<int>::iterator it = s.begin(); it != s.end(); it++) { cout << *it << " "; } cout << endl; } //構造和賦值 void test01() { set<int> s1; s1.insert(10); s1.insert(30); s1.insert(20); s1.insert(40); printSet(s1); //列印 //拷貝構造 set<int>s2(s1); printSet(s2); //列印 //賦值 set<int>s3; //定義 s3 = s2; //賦值 printSet(s3); //列印 } int main() { test01(); system("pause"); return 0; }
說明:
- set容器插入資料時用insert
- set容器插入資料的資料會自動排序
set大小和交換
功能描述:
- 統計set容器大小以及交換set容器
函式原型:
-
size();
//返回容器中元素的數目 -
empty();
//判斷容器是否為空 -
swap(st);
//交換兩個集合容器
舉例:
#include <iostream> #include <set> #include <string> using namespace std; void printSet(set<int> & s) { for (set<int>::iterator it = s.begin(); it != s.end(); it++) { cout << *it << " "; } cout << endl; } //大小 void test01() { set<int> s1; s1.insert(10); s1.insert(30); s1.insert(20); s1.insert(40); if (s1.empty()) { cout << "s1為空" << endl; } else { cout << "s1不為空" << endl; cout << "s1的大小為: " << s1.size() << endl; } } //交換 void test02() { set<int> s1; s1.insert(10); s1.insert(30); printSet(s1); s1.insert(20); printSet(s1); s1.insert(40); printSet(s1); set<int> s2; s2.insert(100); s2.insert(300); printSet(s2); s2.insert(200); printSet(s2); s2.insert(400); printSet(s2); cout << "交換前" << endl; printSet(s1); printSet(s2); cout << endl; cout << "交換後" << endl; s1.swap(s2); printSet(s1); printSet(s2); } int main() { //test01(); test02(); system("pause"); return 0; }
set插入和刪除
功能描述:
- set容器進行插入資料和刪除資料
函式原型:
-
insert(elem);
//在容器中插入元素。 -
clear();
//清除所有元素 -
erase(pos);
//刪除pos迭代器所指的元素,返回下一個元素的迭代器。 -
erase(beg, end);
//刪除區間[beg,end)的所有元素 ,返回下一個元素的迭代器。 -
erase(elem);
//刪除容器中值為elem的元素。
#include <iostream> #include <set> #include <string> using namespace std; void printSet(set<int> & s) { for (set<int>::iterator it = s.begin(); it != s.end(); it++) { cout << *it << " "; } cout << endl; } //插入和刪除 void test01() { set<int> s1; //插入 s1.insert(10); s1.insert(30); s1.insert(20); s1.insert(40); printSet(s1); //刪除 s1.erase(s1.begin()); printSet(s1); s1.erase(30); printSet(s1); //清空 s1.erase(s1.begin(), s1.end()); s1.clear(); printSet(s1); } int main() { test01(); system("pause"); return 0; }
set查詢和統計
功能描述:
- 對set容器進行查詢資料以及統計資料
函式原型:
-
find(key);
//查詢key是否存在,若存在,返回該鍵的元素的迭代器;若不存在,返回set.end(); -
count(key);
//統計key的元素個數
#include <iostream> #include <set> #include <string> using namespace std; void printSet(set<int> & s) { for (set<int>::iterator it = s.begin(); it != s.end(); it++) { cout << *it << " "; } cout << endl; } //查詢和統計 void test01() { set<int> s1; //插入 s1.insert(10); s1.insert(30); s1.insert(20); s1.insert(30); printSet(s1);//自動刪除重複元素 //查詢 set<int>::iterator pos = s1.find(30); if (pos != s1.end()) { cout << "找到了元素 : " << *pos << endl; } else { cout << "未找到元素" << endl; } //統計 int num = s1.count(30); cout << "num = " << num << endl; } int main() { test01(); system("pause"); return 0; }
set和multiset區別
學習目標:
- 掌握set和multiset的區別
區別:
- set不可以插入重複資料,而multiset可以
- set插入資料的同時會返回插入結果,表示插入是否成功
- multiset不會檢測資料,因此可以插入重複資料
程式:
#include <iostream> #include <set> #include <string> using namespace std; //set和multiset區別 void test01() { set<int> s; pair<set<int>::iterator, bool> ret = s.insert(10); if (ret.second) { cout << "第一次插入成功!" << endl; } else { cout << "第一次插入失敗!" << endl; } ret = s.insert(10); if (ret.second) { cout << "第二次插入成功!" << endl; } else { cout << "第二次插入失敗!" << endl; } //multiset multiset<int> ms; ms.insert(10); ms.insert(10); for (multiset<int>::iterator it = ms.begin(); it != ms.end(); it++) { cout << *it << " "; } cout << endl; } int main() { test01(); system("pause"); return 0; }
pair對組建立
功能描述:
- 成對出現的資料,利用對組可以返回兩個資料
兩種建立方式:
pair<type, type> p ( value1, value2 );
pair<type, type> p = make_pair( value1, value2 );
程式:
#include <iostream> #include <set> #include <string> using namespace std; //對組建立 void test01() { pair<string, int> p(string("Tom"), 20); cout << "姓名: " << p.first << " 年齡: " << p.second << endl; pair<string, int> p2 = make_pair("Jerry", 10); cout << "姓名: " << p2.first << " 年齡: " << p2.second << endl; } int main() { test01(); system("pause"); return 0; }
set容器排序
學習目標:
- set容器預設排序規則為從小到大,掌握如何改變排序規則
主要技術點:
利用仿函式,可以改變排序規則 / 可以指定set容器的排序規則
示例一:set存放內建資料型別
程式碼:
#include <iostream> #include <set> #include <string> using namespace std; class MyCompare { public: bool operator()(int v1, int v2) { return v1 > v2; } }; void test01() { set<int> s1; s1.insert(10); s1.insert(40); s1.insert(20); s1.insert(30); s1.insert(50); //預設從小到大 for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) { cout << *it << " "; } cout << endl; //指定排序規則 set<int,MyCompare> s2; //仿函式 s2.insert(10); s2.insert(40); s2.insert(20); s2.insert(30); s2.insert(50); for (set<int, MyCompare>::iterator it = s2.begin(); it != s2.end(); it++) { cout << *it << " "; } cout << endl; } int main() { test01(); system("pause"); return 0; }
示例二: set存放自定義資料型別
程式:
#include <iostream> #include <set> #include <string> using namespace std; class Person { public: Person(string name, int age) { this->m_Name = name; this->m_Age = age; } string m_Name; int m_Age; }; class comparePerson { public: bool operator()(const Person& p1, const Person &p2) { //按照年齡進行排序 降序 return p1.m_Age > p2.m_Age; } }; void test01() { set<Person, comparePerson> s; Person p1("劉備", 23); Person p2("關羽", 27); Person p3("張飛", 25); Person p4("趙雲", 21); // 自動排序 s.insert(p1); s.insert(p2); s.insert(p3); s.insert(p4); for (set<Person, comparePerson>::iterator it = s.begin(); it != s.end(); it++) { cout << "姓名: " << it->m_Name << " 年齡: " << it->m_Age << endl; } } int main() { test01(); system("pause"); return 0; }
map/multiset容器
map基本概念
簡介:
- map中所有元素都是pair
- pair中第一個元素為key(鍵值),起到索引作用,第二個元素為value(實值)
- 所有元素都會根據元素的鍵值自動排序
本質:
- map/multimap屬於關聯式容器,底層結構是用二叉樹實現。
優點:
- 可以根據key值快速找到value值
map和multimap區別:
- map不允許容器中有重複key值元素
- multimap允許容器中有重複key值元素
map構造和賦值
功能描述:
- 對map容器進行構造和賦值操作
函式原型:
構造:
-
map<T1, T2> mp;
//map預設建構函式: -
map(const map &mp);
//拷貝建構函式
賦值:
-
map& operator=(const map &mp);
//過載等號操作符
舉例:
#include <iostream> #include <map> #include <string> using namespace std; void printMap(map<int,int>&m) { for (map<int, int>::iterator it = m.begin(); it != m.end(); it++) { cout << "key = " << it->first << " value = " << it->second << endl; } cout << endl; } void test01() { map<int,int>m; //預設構造 m.insert(pair<int, int>(1, 10)); m.insert(pair<int, int>(2, 20)); m.insert(pair<int, int>(3, 30)); printMap(m); map<int, int>m2(m); //拷貝構造 printMap(m2); map<int, int>m3; m3 = m2; //賦值 printMap(m3); } int main() { test01(); system("pause"); return 0; }
說明:map中所有元素都是成對出現,插入資料時候要使用對組
map大小和交換
功能描述:
- 統計map容器大小以及交換map容器
函式原型:
-
size();
//返回容器中元素的數目 -
empty();
//判斷容器是否為空 -
swap(st);
//交換兩個集合容器
程式:
#include <iostream> #include <map> #include <string> using namespace std; void printMap(map<int,int>&m) { for (map<int, int>::iterator it = m.begin(); it != m.end(); it++) { cout << "key = " << it->first << " value = " << it->second << endl; } cout << endl; } void test01() { map<int, int>m; m.insert(pair<int, int>(1, 10)); m.insert(pair<int, int>(2, 20)); m.insert(pair<int, int>(3, 30)); if (m.empty()) { cout << "m為空" << endl; } else { cout << "m不為空" << endl; cout << "m的大小為: " << m.size() << endl; } } //交換 void test02() { map<int, int>m; m.insert(pair<int, int>(1, 10)); m.insert(pair<int, int>(2, 20)); m.insert(pair<int, int>(3, 30)); map<int, int>m2; m2.insert(pair<int, int>(4, 100)); m2.insert(pair<int, int>(5, 200)); m2.insert(pair<int, int>(6, 300)); cout << "交換前" << endl; printMap(m); printMap(m2); cout << "交換後" << endl; m.swap(m2); printMap(m); printMap(m2); } int main() { test01(); test02(); system("pause"); return 0; }
map插入和刪除
功能描述:
- map容器進行插入資料和刪除資料
函式原型:
-
insert(elem);
//在容器中插入元素。 -
clear();
//清除所有元素 -
erase(pos);
//刪除pos迭代器所指的元素,返回下一個元素的迭代器。 -
erase(beg, end);
//刪除區間[beg,end)的所有元素 ,返回下一個元素的迭代器。 -
erase(key);
//刪除容器中值為key的元素。
#include <iostream> #include <map> #include <string> using namespace std; void printMap(map<int,int>&m) { for (map<int, int>::iterator it = m.begin(); it != m.end(); it++) { cout << "key = " << it->first << " value = " << it->second << endl; } cout << endl; } void test01() { //插入 map<int, int> m; //第一種插入方式 m.insert(pair<int, int>(1, 10)); //第二種插入方式 m.insert(make_pair(2, 20)); //第三種插入方式 m.insert(map<int, int>::value_type(3, 30)); //第四種插入方式 m[4] = 40; printMap(m); //刪除 m.erase(m.begin()); printMap(m); m.erase(3); printMap(m); //清空 m.erase(m.begin(),m.end()); m.clear(); printMap(m); } int main() { test01(); system("pause"); return 0; }
map查詢和統計
功能描述:
- 對map容器進行查詢資料以及統計資料
函式原型:
-
find(key);
//查詢key是否存在,若存在,返回該鍵的元素的迭代器;若不存在,返回set.end(); -
count(key);
//統計key的元素個數
程式:
#include <iostream> #include <map> #include <string> using namespace std; //查詢和統計 void test01() { map<int, int>m; m.insert(pair<int, int>(3, 10)); m.insert(pair<int, int>(2, 20)); m.insert(pair<int, int>(3, 30)); //查詢 map<int, int>::iterator pos = m.find(2); if (pos != m.end()) { cout << "找到了元素 key = " << (*pos).first << " value = " << (*pos).second << endl; } else { cout << "未找到元素" << endl; } //統計 int num = m.count(3); cout << "num = " << num << endl; } int main() { test01(); system("pause"); return 0; }
總結:
- 查詢 --- find (返回的是迭代器)
- 統計 --- count (對於map,結果為0或者1)
map容器排序
學習目標:
- map容器預設排序規則為 按照key值進行 從小到大排序,掌握如何改變排序規則
主要技術點:
- 利用仿函式,可以改變排序規則
程式:
#include <iostream> #include <map> #include <string> using namespace std; class MyCompare { public: bool operator()(int v1, int v2) { return v1 > v2; } }; void test01() { //預設從小到大排序 //利用仿函式實現從大到小排序 map<int, int, MyCompare> m; m.insert(make_pair(1, 10)); m.insert(make_pair(2, 20)); m.insert(make_pair(3, 30)); m.insert(make_pair(4, 40)); m.insert(make_pair(5, 50)); for (map<int, int, MyCompare>::iterator it = m.begin(); it != m.end(); it++) { cout << "key:" << it->first << " value:" << it->second << endl; } } int main() { test01(); system("pause"); return 0; }
案例-員工分組
案例描述:
- 公司今天招聘了10個員工(ABCDEFGHIJ),10名員工進入公司之後,需要指派員工在那個部門工作
- 員工資訊有: 姓名 工資組成;部門分為:策劃、美術、研發
- 隨機給10名員工分配部門和工資
- 通過multimap進行資訊的插入 key(部門編號) value(員工)
- 分部門顯示員工資訊
實現步驟:
- 建立10名員工,放到vector中
- 遍歷vector容器,取出每個員工,進行隨機分組
- 分組後,將員工部門編號作為key,具體員工作為value,放入到multimap容器中
- 分部門顯示員工資訊
#include<iostream> using namespace std; #include <vector> #include <string> #include <map> #include <ctime> /* - 公司今天招聘了10個員工(ABCDEFGHIJ),10名員工進入公司之後,需要指派員工在那個部門工作 - 員工資訊有: 姓名 工資組成;部門分為:策劃、美術、研發 - 隨機給10名員工分配部門和工資 - 通過multimap進行資訊的插入 key(部門編號) value(員工) - 分部門顯示員工資訊 */ #define CEHUA 0 #define MEISHU 1 #define YANFA 2 class Worker { public: string m_Name; int m_Salary; }; void createWorker(vector<Worker>&v) { string nameSeed = "ABCDEFGHIJ"; for (int i = 0; i < 10; i++) { Worker worker; worker.m_Name = "員工"; worker.m_Name += nameSeed[i]; worker.m_Salary = rand() % 10000 + 10000; // 10000 ~ 19999 //將員工放入到容器中 v.push_back(worker); } } //員工分組 void setGroup(vector<Worker>&v,multimap<int,Worker>&m) { for (vector<Worker>::iterator it = v.begin(); it != v.end(); it++) { //產生隨機部門編號 int deptId = rand() % 3; // 0 1 2 //將員工插入到分組中 //key部門編號,value具體員工 m.insert(make_pair(deptId, *it)); } } void showWorkerByGourp(multimap<int,Worker>&m) { // 0 A B C 1 D E 2 F G ... cout << "策劃部門:" << endl; multimap<int,Worker>::iterator pos = m.find(CEHUA); int count = m.count(CEHUA); // 統計具體人數 int index = 0; for (; pos != m.end() && index < count; pos++ , index++) { cout << "姓名: " << pos->second.m_Name << " 工資: " << pos->second.m_Salary << endl; } cout << "----------------------" << endl; cout << "美術部門: " << endl; pos = m.find(MEISHU); count = m.count(MEISHU); // 統計具體人數 index = 0; for (; pos != m.end() && index < count; pos++, index++) { cout << "姓名: " << pos->second.m_Name << " 工資: " << pos->second.m_Salary << endl; } cout << "----------------------" << endl; cout << "研發部門: " << endl; pos = m.find(YANFA); count = m.count(YANFA); // 統計具體人數 index = 0; for (; pos != m.end() && index < count; pos++, index++) { cout << "姓名: " << pos->second.m_Name << " 工資: " << pos->second.m_Salary << endl; } } int main() { srand((unsigned int)time(NULL)); //1、建立員工 vector<Worker>vWorker; createWorker(vWorker); //2、員工分組 multimap<int, Worker>mWorker; setGroup(vWorker, mWorker); //3、分組顯示員工 showWorkerByGourp(mWorker); ////測試 //for (vector<Worker>::iterator it = vWorker.begin(); it != vWorker.end(); it++) //{ // cout << "姓名: " << it->m_Name << " 工資: " << it->m_Salary << endl; //} system("pause"); return 0; }
STL- 函式物件
函式物件
函式物件概念
概念:
- 過載函式呼叫操作符的類,其物件常稱為函式物件
- 函式物件使用過載的()時,行為類似函式呼叫,也叫仿函式
本質:
函式物件(仿函式)是一個類,不是一個函式
函式物件使用
特點:
- 函式物件在使用時,可以像普通函式那樣呼叫, 可以有引數,可以有返回值
- 函式物件超出普通函式的概念,函式物件可以有自己的狀態
- 函式物件可以作為引數傳遞
#include<iostream> using namespace std; #include <string> //1、函式物件在使用時,可以像普通函式那樣呼叫, 可以有引數,可以有返回值 class MyAdd { public : int operator()(int v1,int v2) { return v1 + v2; } }; void test01() { MyAdd myAdd; cout << myAdd(10, 10) << endl; } //2、函式物件可以有自己的狀態 class MyPrint { public: MyPrint() { count = 0; } void operator()(string test) { cout << test << endl; count++; //統計使用次數 } int count; //內部自己的狀態 }; void test02() { MyPrint myPrint; myPrint("hello world"); myPrint("hello world"); myPrint("hello world"); cout << "myPrint呼叫次數為: " << myPrint.count << endl; } //3、函式物件可以作為引數傳遞 void doPrint(MyPrint &mp , string test) { mp(test); cout << "myPrint呼叫次數為: " << mp.count << endl; } void test03() { MyPrint myPrint; doPrint(myPrint, "Hello C++"); } int main() { test01(); test02(); test03(); system("pause"); return 0; }