術語:概念ios
術語:模型算法
用概念作模板參數名數組
例如安全
表示insertionSort這樣一個函數模板的原型:數據結構
template <class Sortable> void insertionSort(Sortable a[], int n);
標準模板庫(Standard Template Library,簡稱STL)提供了一些很是經常使用的數據結構和算法less
STL簡介dom
標準模板庫(Standard Template Library,簡稱STL)定義了一套概念體系,爲泛型程序設計提供了邏輯基礎數據結構和算法
STL中的各個類模板、函數模板的參數都是用這個體系中的概念來規定的。ide
使用STL的模板時,類型參數既能夠是C++標準庫中已有的類型,也能夠是自定義的類型——只要這些類型是所要求概念的模型。函數
STL的基本組件
容器(container)
迭代器(iterator)
函數對象(function object)
算法(algorithms)
STL的基本組件間的關係
Iterators(迭代器)是算法和容器的橋樑。
將迭代器做爲算法的參數、經過迭代器來訪問容器而不是把容器直接做爲算法的參數。
將函數對象做爲算法的參數而不是將函數所執行的運算做爲算法的一部分。
使用STL中提供的或自定義的迭代器和函數對象,配合STL的算法,能夠組合出各類各樣的功能。
STL的基本組件——容器(container)
容納、包含一組元素的對象。
基本容器類模板
unorderedset (無序集合)、unorderedmultiset(無序多重集合)
unorderedmap(無序映射)、unordermultimap(無序多重映射)
set(集合)、multiset(多重集合)、map(映射)、multimap(多重映射)
array(數組)、vector(向量)、deque(雙端隊列)、forward_list(單鏈表)、list(列表)
順序容器
(有序)關聯容器
無序關聯容器
容器適配器
stack(棧)、queue(隊列)、priority_queue(優先隊列)
使用容器,須要包含對應的頭文件
STL的基本組件——迭代器(iterator)
迭代器是泛化的指針,提供了順序訪問容器中每一個元素的方法
提供了順序訪問容器中每一個元素的方法;
可使用「++」運算符來得到指向下一個元素的迭代器;
可使用「*」運算符訪問一個迭代器所指向的元素,若是元素類型是類或結構體,還可使用「->」運算符直接訪問該元素的一個成員;
有些迭代器還支持經過「--」運算符得到指向上一個元素的迭代器;
迭代器是泛化的指針:指針也具備一樣的特性,所以指針自己就是一種迭代器;
使用獨立於STL容器的迭代器,須要包含頭文件
。STL的基本組件——函數對象(function object)
一個行爲相似函數的對象,對它能夠像調用函數同樣調用。
函數對象是泛化的函數:任何普通的函數和任何重載了「()」 運算符的類的對象均可以做爲函數對象使用
使用STL的函數對象,須要包含頭文件
STL的基本組件——算法(algorithms)
STL包括70多個算法
例如:排序算法,消除算法,計數算法,比較算法,變換算法,置換算法和容器管理等
能夠普遍用於不一樣的對象和內置的數據類型。
使用STL的算法,須要包含頭文件。
例10-1從標準輸入讀入幾個整數,存入向量容器,輸出它們的相反數
例10-1:STL程序實例
transform算法的一種實現:
template <class InputIterator, class OutputIterator, class UnaryFunction> OutputIterator transform(InputIterator first, InputIterator last, OutputIterator result, UnaryFunction op) { for (;first != last; ++first, ++result) *result = op(*first); return result; }
transform算法順序遍歷first和last兩個迭代器所指向的元素;
將每一個元素的值做爲函數對象op的參數;
將op的返回值經過迭代器result順序輸出;
遍歷完成後result迭代器指向的是輸出的最後一個元素的下一個位置,transform會將該迭代器返回
迭代器是算法和容器的橋樑
迭代器用做訪問容器中的元素
算法不直接操做容器中的數據,而是經過迭代器間接操做
算法和容器獨立
增長新的算法,無需影響容器的實現
增長新的容器,原有的算法也能適用
輸入流迭代器
istream_iterator<T>
以輸入流(如cin)爲參數構造
可用*(p++)得到下一個輸入的元素
輸出流迭代器
ostream_iterator<T>
構造時須要提供輸出流(如cout)
可用(*p++) = x將x輸出到輸出流
兩者都屬於適配器
適配器是用來爲已有對象提供新的接口的對象
輸入流適配器和輸出流適配器爲流對象提供了迭代器的接口
例10-2從標準輸入讀入幾個實數,分別將它們的平方輸出
//10_2.cpp #include <iterator> #include <iostream> #include <algorithm> using namespace std; //求平方的函數 double square(double x) { return x * x; } int main() { //從標準輸入讀入若干個實數,分別將它們的平方輸出 transform(istream_iterator<double>(cin), istream_iterator<double>(), ostream_iterator<double>(cout, "\t"), square); cout << endl; return 0; }
迭代器支持的操做
迭代器是泛化的指針,提供了相似指針的操做(諸如++、*、->運算符)
輸入迭代器
能夠用來從序列中讀取數據,如輸入流迭代器
輸出迭代器
容許向序列中寫入數據,如輸出流迭代器
前向迭代器
既是輸入迭代器又是輸出迭代器,而且能夠對序列進行單向的遍歷
雙向迭代器
與前向迭代器類似,可是在兩個方向上均可以對數據遍歷
隨機訪問迭代器
也是雙向迭代器,但可以在序列中的任意兩個位置之間進行跳轉,如指針、使用vector的begin()、end()函數獲得的迭代器
兩個迭代器表示一個區間:[p1, p2)
STL算法常以迭代器的區間做爲輸入,傳遞輸入數據
合法的區間
p1通過n次(n > 0)自增(++)操做後知足p1 == p2
區間包含p1,但不包含p2
例10-3 綜合運用幾種迭代器的示例
程序涉及到輸入迭代器、輸出迭代器、隨機訪問迭代器這三個迭代器概念,而且之前兩個概念爲基礎編寫了一個通用算法。
//10_3.cpp #include <algorithm> #include <iterator> #include <vector> #include <iostream> using namespace std; //未來自輸入迭代器的n個T類型的數值排序,將結果經過輸出迭代器result輸出 template <class T, class InputIterator, class OutputIterator> void mySort(InputIterator first, InputIterator last, OutputIterator result) { //經過輸入迭代器將輸入數據存入向量容器s中 vector<T> s; for (;first != last; ++first) s.push_back(*first); //對s進行排序,sort函數的參數必須是隨機訪問迭代器 sort(s.begin(), s.end()); copy(s.begin(), s.end(), result); //將s序列經過輸出迭代器輸出 } int main() { //將s數組的內容排序後輸出 double a[5] = { 1.2, 2.4, 0.8, 3.3, 3.2 }; mySort<double>(a, a + 5, ostream_iterator<double>(cout, " ")); cout << endl; //從標準輸入讀入若干個整數,將排序後的結果輸出 mySort<int>(istream_iterator<int>(cin), istream_iterator<int>(), ostream_iterator<int>(cout, " ")); cout << endl; return 0; }
運行結果:
0.8 1.2 2.4 3.2 3.3
2 -4 5 8 -1 3 6 -5
-5 -4 -1 2 3 5 6 8
advance(p, n)
對p執行n次自增操做
distance(first, last)
計算兩個迭代器first和last的距離,即對first執行多少次「++」操做後可以使得first == last
容器類是容納、包含一組元素或元素集合的對象。
基於容器中元素的組織方式:順序容器、關聯容器
按照與容器所關聯的迭代器類型劃分:可逆容器隨機訪問容器
容器
unorderedset (無序集合)、unorderedmultiset(無序多重集合)
unorderedmap(無序映射)、unordermultimap(無序多重映射)
set(集合)、multiset(多重集合)、map(映射)、multimap(多重映射)
array(數組)、vector(向量)、deque(雙端隊列)、forward_list(單鏈表)、list(列表)
順序容器
(有序)關聯容器
無序關聯容器
容器的通用功能
容器的通用功能
用默認構造函數構造空容器
支持關係運算符:==、!=、<、<=、>、>=
begin()、end():得到容器首、尾迭代器
clear():將容器清空
empty():判斷容器是否爲空
size():獲得容器元素個數
s1.swap(s2):將s1和s2兩容器內容交換
相關數據類型(S表示容器類型)
S::iterator:指向容器元素的迭代器類型
S::const_iterator:常迭代器類型
對可逆容器的訪問
STL爲每一個可逆容器都提供了逆向迭代器,逆向迭代器能夠經過下面的成員函數獲得:
rbegin() :指向容器尾的逆向迭代器
rend():指向容器首的逆向迭代器
逆向迭代器的類型名的表示方式以下:
S::reverse_iterator:逆向迭代器類型
S::constreverseiterator:逆向常迭代器類型
隨機訪問容器
隨機訪問容器支持對容器的元素進行隨機訪問
s[n]:得到容器s的第n個元素
順序容器
順序容器的接口(不包含單向鏈表(forward_list)和數組(array))
例10-4 順序容器的基本操做
//10_4.cpp #include <iostream> #include <list> #include <deque> //輸出指定的順序容器的元素 template <class T> void printContainer(const char* msg, const T& s) { cout << msg << ": "; copy(s.begin(), s.end(), ostream_iterator<int>(cout, " ")); cout << endl; } int main() { //從標準輸入讀入10個整數,將它們分別從s的頭部加入 deque<int> s; for (int i = 0; i < 10; i++) { int x; cin >> x; s.push_front(x); } printContainer("deque at first", s); //用s容器的內容的逆序構造列表容器l list<int> l(s.rbegin(), s.rend()); printContainer("list at first", l); //將列表容器l的每相鄰兩個元素順序顛倒 list<int>::iterator iter = l.begin(); while (iter != l.end()) { int v = *iter; iter = l.erase(iter); l.insert(++iter, v); } printContainer("list at last", l); //用列表容器l的內容給s賦值,將s輸出 s.assign(l.begin(), l.end()); printContainer("deque at last", s); return 0; }
運行結果以下: 0 9 8 6 4 3 2 1 5 4 deque at first: 4 5 1 2 3 4 6 8 9 0 list at first: 0 9 8 6 4 3 2 1 5 4 list at last: 9 0 6 8 3 4 1 2 4 5 deque at last: 9 0 6 8 3 4 1 2 4 5
例10-5 奇偶排序
先按照從大到小順序輸出奇數,再按照從小到大順序輸出偶數。
// 頭部分省略 int main() { istream_iterator<int> i1(cin), i2; //創建一對輸入流迭代器 vector<int> s1(i1, i2); //經過輸入流迭代器從標準輸入流中輸入數據 sort(s1.begin(), s1.end()); //將輸入的整數排序 deque<int> s2; //如下循環遍歷s1 for (vector<int>::iterator iter = s1.begin(); iter != s1.end(); ++iter) { if (*iter % 2 == 0) //偶數放到s2尾部 s2.push_back(*iter); else //奇數放到s2首部 s2.push_front(*iter); } //將s2的結果輸出 copy(s2.begin(), s2.end(), ostream_iterator<int>(cout, " ")); cout << endl; return 0; }
列表(list)
接合(splice)操做
s1.splice(p, s2, q1, q2):將s2中[q1, q2)移動到s1中p所指向元素以前
// 頭部分省略 int main() { string names1[] = { "Alice", "Helen", "Lucy", "Susan" }; string names2[] = { "Bob", "David", "Levin", "Mike" }; //用names1數組的內容構造列表s1 list<string> s1(names1, names1 + 4); //用names2數組的內容構造列表s2 list<string> s2(names2, names2 + 4); //將s1的第一個元素放到s2的最後 s2.splice(s2.end(), s1, s1.begin()); list<string>::iterator iter1 = s1.begin(); //iter1指向s1首 advance(iter1, 2); //iter1前進2個元素,它將指向s1第3個元素 list<string>::iterator iter2 = s2.begin(); //iter2指向s2首 ++iter2; //iter2前進1個元素,它將指向s2第2個元素 list<string>::iterator iter3 = iter2; //用iter2初始化iter3 advance(iter3, 2); //iter3前進2個元素,它將指向s2第4個元素 //將[iter2, iter3)範圍內的結點接到s1中iter1指向的結點前 s1.splice(iter1, s2, iter2, iter3); //分別將s1和s2輸出 copy(s1.begin(), s1.end(), ostream_iterator<string>(cout, " ")); cout << endl; copy(s2.begin(), s2.end(), ostream_iterator<string>(cout, " ")); cout << endl; return 0; }
單向鏈表(forward_list)
數組(array)
順序容器的比較
順序容器的插入迭代器
例:
list<int> s; back_inserter iter(s); *(iter++) = 5; //經過iter把5插入s末尾
順序容器的適配器
棧和隊列模板
棧模板
template <class T, class Sequence = deque<T> > class stack;
隊列模板
template <class T, class FrontInsertionSequence = deque<T> > class queue;
棧和隊列共同支持的操做
棧和隊列不一樣的操做
例10-7 利用棧反向輸出單詞
//10_7.cpp, 省略頭部分 int main() { stack<char> s; string str; cin >> str; //從鍵盤輸入一個字符串 //將字符串的每一個元素順序壓入棧中 for (string::iterator iter = str.begin(); iter != str.end(); ++iter) s.push(*iter); //將棧中的元素順序彈出並輸出 while (!s.empty()) { cout << s.top(); s.pop(); } cout << endl; return 0; } 運行結果以下: congratulations snoitalutargnoc
優先級隊列
優先級隊列也像棧和隊列同樣支持元素的壓入和彈出,但元素彈出的順序與元素的大小有關,每次彈出的老是容器中最「大」的一個元素。
template <class T, class Sequence = vector<T> > class priority_queue;
優先級隊列的基礎容器必須是支持隨機訪問的順序容器。
例10-8 細胞分裂模擬
一種細胞在誕生(即上次分裂)後會在500到2000秒內分裂爲兩個細胞,每一個細胞又按照一樣的規律繼續分裂。
// 10.8.cpp, 頭部分省略 const int SPLIT_TIME_MIN = 500; //細胞分裂最短期 const int SPLIT_TIME_MAX = 2000; //細胞分裂最長時間 class Cell; priority_queue<Cell> cellQueue; class Cell { //細胞類 private: static int count; //細胞總數 int id; //當前細胞編號 int time; //細胞分裂時間 public: Cell(int birth) : id(count++) { //birth爲細胞誕生時間 //初始化,肯定細胞分裂時間 time = birth + (rand() % (SPLIT_TIME_MAX - SPLIT_TIME_MIN))+ SPLIT_TIME_MIN; } int getId() const { return id; } //獲得細胞編號 int getSplitTime() const { return time; } //獲得細胞分裂時間 bool operator < (const Cell& s) const //定義「<」 { return time > s.time; } void split() { //細胞分裂 Cell child1(time), child2(time); //創建兩個子細胞 cout << time << "s: Cell #" << id << " splits to #" << child1.getId() << " and #" << child2.getId() << endl; cellQueue.push(child1); //將第一個子細胞壓入優先級隊列 cellQueue.push(child2); //將第二個子細胞壓入優先級隊列 } }; int Cell::count = 0; int main() { srand(static_cast<unsigned>(time(0))); int t; //模擬時間長度 cout << "Simulation time: "; cin >> t; cellQueue.push(Cell(0)); //將第一個細胞壓入優先級隊列 while (cellQueue.top().getSplitTime() <= t) { cellQueue.top().split(); //模擬下一個細胞的分裂 cellQueue.pop(); //將剛剛分裂的細胞彈出 } return 0; } /* 運行結果以下: Simulation time: 5000 971s: Cell #0 splits to #1 and #2 1719s: Cell #1 splits to #3 and #4 1956s: Cell #2 splits to #5 and #6 2845s: Cell #6 splits to #7 and #8 3551s: Cell #3 splits to #9 and #10 3640s: Cell #4 splits to #11 and #12 3919s: Cell #5 splits to #13 and #14 4162s: Cell #10 splits to #15 and #16 4197s: Cell #8 splits to #17 and #18 4317s: Cell #7 splits to #19 and #20 4686s: Cell #13 splits to #21 and #22 4809s: Cell #12 splits to #23 and #24 4818s: Cell #17 splits to #25 and #26 */
關聯容器的特色和接口
關聯容器概念圖
四種關聯容器
無序關聯容器
集合用來存儲一組無重複的元素。因爲集合的元素自己是有序的,能夠高效地查找指定元素,也能夠方便地獲得指定大小範圍的元素在容器中所處的區間。
例10-9
輸入一串實數,將重複的去掉,取最大和最小者的中值,分別輸出小於等於此中值和大於等於此中值的實數
//10_9.cpp #include <set> #include <iterator> #include <utility> #include <iostream> using namespace std; int main() { set<double> s; while (true) { double v; cin >> v; if (v == 0) break; //輸入0表示結束 //嘗試將v插入 pair<set<double>::iterator,bool> r=s.insert(v); if (!r.second) //若是v已存在,輸出提示信息 cout << v << " is duplicated" << endl; } //獲得第一個元素的迭代器 set<double>::iterator iter1=s.begin(); //獲得末尾的迭代器 set<double>::iterator iter2=s.end(); //獲得最小和最大元素的中值 double medium=(*iter1 + *(--iter2)) / 2; //輸出小於或等於中值的元素 cout<< "<= medium: " copy(s.begin(), s.upper_bound(medium), ostream_iterator<double>(cout, " ")); cout << endl; //輸出大於或等於中值的元素 cout << ">= medium: "; copy(s.lower_bound(medium), s.end(), ostream_iterator<double>(cout, " ")); cout << endl; return 0; } 運行結果以下: 1 2.5 5 3.5 5 7 9 2.5 0 5 is duplicated 2.5 is duplicated <= medium: 1 2.5 3.5 5 >= medium: 5 7 9
例10-10
有五門課程,每門都有相應學分,從中選擇三門,輸出學分總和
//10_10.cpp #include <iostream> #include <map> #include <string> #include <utility> using namespace std; int main() { map<string, int> courses; //將課程信息插入courses映射中 courses.insert(make_pair("CSAPP", 3)); courses.insert(make_pair("C++", 2)); courses.insert(make_pair("CSARCH", 4)); courses.insert(make_pair("COMPILER", 4)); courses.insert(make_pair("OS", 5)); int n = 3; //剩下的可選次數 int sum = 0; //學分總和 while (n > 0) { string name; cin >> name; //輸入課程名稱 map<string, int>::iterator iter = courses.find(name);//查找課程 if (iter == courses.end()) { //判斷是否找到 cout << name << " is not available" << endl; } else { sum += iter->second; //累加學分 courses.erase(iter); //將剛選過的課程從映射中刪除 n--; } } cout << "Total credit: " << sum << endl; //輸出總學分 return 0; } 運行結果以下: C++ COMPILER C++ C++ is not available CSAPP Total credit: 9
例10-11
統計一句話中每一個字母出現的次數
// 10_11.cpp #include <iostream> #include <map> #include <cctype> using namespace std; int main() { map<char, int> s; //用來存儲字母出現次數的映射 char c; //存儲輸入字符 do { cin >> c; //輸入下一個字符 if (isalpha(c)){ //判斷是不是字母 c = tolower(c); //將字母轉換爲小寫 s[c]++; //將該字母的出現頻率加1 } } while (c != '.'); //碰到「.」則結束輸入 //輸出每一個字母出現次數 for (map<char, int>::iterator iter = s.begin(); iter != s.end(); ++iter) cout << iter->first << " " << iter->second << " "; cout << endl; return 0; }
多重集合是容許有重複元素的集合,多重映射是容許一個鍵對應多個附加數據的映射。
多重集合與集合、多重映射與映射的用法差很少,只在幾個成員函數上有細微差別,其差別主要表如今去除了鍵必須惟一的限制。
例10-12 上課時間查詢
//10_12.cpp #include <iostream> #include <map> #include <utility> #include <string> using namespace std; int main() { multimap<string, string> courses; typedef multimap<string, string>::iterator CourseIter; //將課程上課時間插入courses映射中 courses.insert(make_pair("C++", "2-6")); courses.insert(make_pair("COMPILER", "3-1")); courses.insert(make_pair("COMPILER", "5-2")); courses.insert(make_pair("OS", "1-2")); courses.insert(make_pair("OS", "4-1")); courses.insert(make_pair("OS", "5-5")); //輸入一個課程名,直到找到該課程爲止,記下每週上課次數 string name; int count; do { cin >> name; count = courses.count(name); if (count == 0) cout << "Cannot find this course!" << endl; } while (count == 0); //輸出每週上課次數和上課時間 cout << count << " lesson(s) per week: "; pair<CourseIter, CourseIter> range = courses.equal_range(name); for (CourseIter iter = range.first; iter != range.second; ++iter) cout << iter->second << " "; cout << endl; return 0; } 運行結果以下: JAVA Cannot find this course! OS 3 lesson(s) per week: 1-2 4-1 5-5
一個行爲相似函數的對象
能夠沒有參數,也能夠帶有若干參數
其功能是獲取一個值,或者改變操做的狀態。
例
普通函數就是函數對象
重載了「()」運算符的類的實例是函數對象
函數對象概念圖
例10-1三、例10-14:
使用兩種方式定義表示乘法的函數對象
經過定義普通函數(例10-13)
經過重載類的「()」運算符(例10-14)
用到如下算法:
template<class InputIterator, class Type, class BinaryFunction> Type accumulate(InputIterator first, InputIterator last, Type val, BinaryFunction binaryOp);
對[first, last)區間內的數據進行累「加」,binaryOp爲用二元函數對象表示的「加」運算符,val爲累「加」的初值
例10-13
#include <iostream> #include <numeric> //包含數值算法頭文件 using namespace std; //定義一個普通函數 int mult(int x, int y) { return x * y; }; int main() { int a[] = { 1, 2, 3, 4, 5 }; const int N = sizeof(a) / sizeof(int); cout << "The result by multipling all elements in a is " << accumulate(a, a + N, 1, mult) << endl; return 0; }
例10-14
//10_14.cpp #include <iostream> #include <numeric> //包含數值算法頭文件 using namespace std; class MultClass{ //定義MultClass類 public: //重載操做符operator() int operator() (int x, int y) const { return x * y; } }; int main() { int a[] = { 1, 2, 3, 4, 5 }; const int N = sizeof(a) / sizeof(int); cout << "The result by multipling all elements in a is " << accumulate(a, a + N, 1, MultClass()) //將類multclass傳遞給通用算法 << endl; return 0; }
STL提供的函數對象
用於算術運算的函數對象:
一元函數對象(一個參數) :negate
二元函數對象(兩個參數) :plus、minus、multiplies、divides、modulus
用於關係運算、邏輯運算的函數對象(要求返回值爲bool)
一元謂詞(一個參數):logical_not
二元謂詞(兩個參數):equalto、notequalto、greater、less、greaterequal、lessequal、logicaland、logical_or
例10-15 利用STL標準函數對象
//10_15.cpp #include <iostream> #include <numeric> //包含數值算法頭文件 #include <functional> //包含標準函數對象頭文件 using namespace std; int main() { int a[] = { 1, 2, 3, 4, 5 }; const int N = sizeof(a) / sizeof(int); cout << "The result by multipling all elements in A is 「 << accumulate(a, a + N, 1, multiplies<int>()) << endl; //將標準函數對象傳遞給通用算法 return 0; }
例10-16利用STL中的二元謂詞函數對象
// 10_16.cpp #include <functional> #include<iostream> #include<vector> #include<algorithm> using namespace std; int main() { int intArr[] = { 30, 90, 10, 40, 70, 50, 20, 80 }; const int N = sizeof(intArr) / sizeof(int); vector<int> a(intArr, intArr + N); cout << "before sorting:" << endl; copy(a.begin(),a.end(),ostream_iterator<int>(cout,"\t")); cout << endl; sort(a.begin(), a.end(), greater<int>()); cout << "after sorting:" << endl; copy(a.begin(),a.end(),ostream_iterator<int>(cout,"\t")); cout << endl; return 0; }
綁定適配器
例10-17:函數適配器實例——找到數組中第一個大於40的元素
//10_17.cpp #include <functional> #include<iostream> #include<vector> #include<algorithm> using namespace std; int main() { int intArr[] = { 30, 90, 10, 40, 70, 50, 20, 80 }; const int N = sizeof(intArr) / sizeof(int); vector<int> a(intArr, intArr + N); vector<int>::iterator p = find_if(a.begin(), a.end(), bind2nd(greater<int>(), 40)); if (p == a.end()) cout << "no element greater than 40" << endl; else cout << "first element greater than 40 is: " << *p << endl; return 0; } 注: find_if算法在STL中的原型聲明爲: template<class InputIterator, class UnaryPredicate> InputIterator find_if(InputIterator first, InputIterator last, UnaryPredicate pred); 它的功能是查找數組[first, last)區間中第一個pred(x)爲真的元素。
組合適配器
例10-18 ptr_fun、not1和not2產生函數適配器實例
// 10_18.cpp #include <functional> #include<iostream> #include<vector> #include<algorithm> using namespace std; bool g(int x, int y) { return x > y; } int main() { int intArr[] = { 30, 90, 10, 40, 70, 50, 20, 80 }; const int N = sizeof(intArr) / sizeof(int); vector<int> a(intArr, intArr + N); vector<int>::iterator p; p = find_if(a.begin(), a.end(), bind2nd(ptr_fun(g), 40)); if (p == a.end()) cout << "no element greater than 40" << endl; else cout << "first element greater than 40 is: " << *p << endl; p = find_if(a.begin(), a.end(), not1(bind2nd(greater<int>(), 15))); if (p == a.end()) cout << "no element is not greater than 15" << endl; else cout << "first element that is not greater than 15 is: " << *p << endl; p = find_if(a.begin(), a.end(), bind2nd(not2(greater<int>()), 15)); if (p == a.end()) cout << "no element is not greater than 15" << endl; else cout << "first element that is not greater than 15 is: " << *p << endl; return 0; }
例10-19 成員函數適配器實例
//10_19.cpp #include <functional> #include <iostream> #include <vector> #include <algorithm> using namespace std; struct Car { int id; Car(int id) { this->id = id; } void display() const { cout << "car " << id << endl; } }; int main() { vector<Car *> pcars; vector<Car> cars; for (int i = 0; i < 5; i++) pcars.push_back(new Car(i)); for (int i = 5; i < 10; i++) cars.push_back(Car(i)); cout << "elements in pcars: " << endl; for_each(pcars.begin(), pcars.end(), std::mem_fun(&Car::display)); cout << endl; cout << "elements in cars: " << endl; for_each(cars.begin(), cars.end(), std::mem_fun_ref(&Car::display)); cout << endl; for (size_t i = 0; i < pcars.size(); ++i) delete pcars[i]; return 0; }
STL算法特色
STL算法自己是一種函數模版
經過迭代器得到輸入數據
經過函數對象對數據進行處理
經過迭代器將結果輸出
STL算法是通用的,獨立於具體的數據類型、容器類型
不可變序列算法
可變序列算法
排序和搜索算法
數值算法
不直接修改所操做的容器內容的算法
用於查找指定元素、比較兩個序列是否相等、對元素進行計數等
例:
template<class InputIterator, class UnaryPredicate> InputIterator find_if(InputIterator first, InputIterator last, UnaryPredicate pred);
查找[first, last)區間內pred(x)爲真的首個元素
能夠修改它們所操做的容器對象
包括對序列進行復制、刪除、替換、倒序、旋轉、交換、分割、去重、填充、洗牌的算法及生成一個序列的算法
例:
template<class ForwardIterator, class T> InputIterator find_if(ForwardIterator first, ForwardIterator last, const T& x);
將[first, last)區間內的元素所有改寫爲x。
對序列進行排序
對兩有序序列進行合併
對有序序列進行搜索
有序序列的集合操做
堆算法
例:
template <class RandomAccessIterator , class UnaryPredicate> void sort(RandomAccessIterator first, RandomAccessIterator last, UnaryPredicate comp);
以函數對象comp爲「<」,對 [first, last)區間內的數據進行排序
求序列中元素的「和」、部分「和」、相鄰元素的「差」或兩序列的內積
求「和」的「+」、求「差」的「-」以及求內積的「+」和「·」均可由函數對象指定
例:
template<class InputIterator, class OutputIterator, class BinaryFunction> OutputIterator partial_sum(InputIterator first, InputIterator last, OutputIterator result, BinaryFunction op);
對[first, last)內的元素求部分「和」(所謂部分「和」,是一個長度與輸入序列相同的序列,其第n項爲輸入序列前n個元素的「和」),以函數對象op爲「+」運算符,結果經過result輸出,返回的迭代器指向輸出序列最後一個元素的下一個元素
算法應用舉例
例10-20——例10-23演示了幾類算法的應用。
詳見教材第10章