C++學習:STL-介面卡
阿新 • • 發佈:2019-01-06
一、介面卡分類二、容器介面卡三、迭代器介面卡四、演算法介面卡介面卡是一種設計模式。一、介面卡分類 容器介面卡: stack 預設基於deque容器實現 queue 預設基於deque容器實現 priority_queue 預設基於vector容器實現迭代器介面卡 流迭代器 反向迭代器 插入迭代器演算法介面卡(函式介面卡) 繫結器 否定器 成員函式介面卡介面卡並不是第一類容器,因為它們並沒有提供與元素的儲存形式有關的真正資料結構實現,並且介面卡不支援迭代器。介面卡的優點是:能夠使程式設計師選擇一種合適的底層資料結構。這三個介面卡類都提供了成員函式push和pop,能夠在每個介面卡資料結構中正確地插入和刪除元素。二、容器介面卡 沒有full的方法,是因為可以無限放資料。 stack queue priority_queuefront 0 1 0 //返回佇列中的第一個元素top 1 0 1 empty 1 1 1 size 1 1 1 push 1 1 1pop 1 1 1 emplace 1 1 1swap 1 1 1queue的使用 先進先出 #include <iostream>#include <queue>using std::cout;using std::endl;using std::queue;int main(void){ queue<int> queInt; for(int idx = 0; idx < 10; ++idx){ queInt.push(idx); //元素入隊 cout << queInt.back() << "已經入隊" << endl; } cout << queInt.size() << "個元素已經入隊" << endl; //當前佇列中有多少元素 while(!queInt.empty()){ //不為空 cout << queInt.front() << "出隊" << endl; //返回佇列中的第一個元素 queInt.pop(); //出隊 } cout << queInt.size() << endl; return 0;}priority_queue的使用 優先順序佇列。satck和queue不會根據優先順序排序。優先順序佇列會排序。預設情況下采用"<"進行排序。採用堆排序進行調整。堆頂元素優先順序最高。所以priority_queue底層採用vector實現,因為二叉樹容易使用陣列實現。例1:預設情況下使用"<"進行排序。#include <iostream>#include <queue>#include <utility>#include <vector>using std::cout;using std::endl;using std::priority_queue;using std::pair;using std::vector;int main(void){ int arr[10] = {0, 1, 3, 2, 5, 6, 9, 8, 7, 4}; priority_queue<int> pqueInt; //建立優先順序佇列 for(int idx = 0; idx != 10; ++idx){ pqueInt.push(arr[idx]); //入隊。入隊的時候,就會比較,然後按照優先順序進行插入。 cout << pqueInt.top() << "是優先級別最高的" << endl; //打印出當前優先順序最高的元素。優先順序佇列採用堆排序進行元素的調 整。預設情況下,比較函式是"<"符號。堆頂的元素要與新進來的元素 比較,如果為true(堆頂<新元素),則將新元素放到堆頂,然後調整堆。 如果為false,則放到最後。如1進來時,0<1,滿足條件,則調整堆,1成為堆 頂。所以採用"<",數字越大優先順序越高。 } while(!pqueInt.empty()){ cout << pqueInt.top() << "出隊" << endl; //獲取隊首元素(優先順序最高的元素) pqueInt.pop(); //出隊:9 8 7 6 5 4 3 2 1 0 } return 0;}例2:自定義型別,過載比較函式#include <iostream>#include <queue>#include <utility>#include <vector>using std::cout;using std::endl;using std::priority_queue;using std::pair;using std::vector;struct MyCompare{ bool operator()(const pair<int, bool> & lhs,const pair<int, bool> & rhs){ //定義一個類,過載函式呼叫運算子 return lhs.first > rhs.first; }};int main(void){ priority_queue<pair<int, bool>,vector<pair<int, bool> >,MyCompare> quePair; //建立優先順序佇列,儲存的是pair. quePair.push(std::make_pair(5, true)); //make_pair的返回值是pair。將5和true拼成一個pair,並返回 quePair.push(std::make_pair(3, false)); quePair.push(std::make_pair(7, true)); while(!quePair.empty()){ const pair<int, bool> & elem = quePair.top(); //elem是pair型別。pop的返回值是const的引用。 cout << elem.first << "-->" << elem.second << endl; quePair.pop(); //3-->0 5-->1 7-->1 } cout << endl; return 0;}三、迭代器介面卡 反向迭代器的使用反向迭代器的開始位置在最後面,最後位置在最前面。例:#include <iostream>#include <vector>#include <iterator>using std::cout;using std::endl;using std::vector;using std::ostream_iterator;int main(void){ vector<int> vecInt = {1, 2, 3, 4, 5}; ostream_iterator<int> osi(cout, " "); //定義輸出流迭代器 vector<int>::reverse_iterator rit = vecInt.rbegin(); //定義反向迭代器。 copy(rit, vecInt.rend(), osi); //5 4 3 2 1 。copy演算法,將rit到vecInt.end()的資料放到osi開始的容器中。 cout << endl; return 0;}插入迭代器的使用 插入迭代器分為:頭插法迭代器、尾插法迭代器、中間插入迭代器。例: #include <iostream>#include <iterator>#include <vector>#include <list>using std::cout;using std::endl;using std::vector;using std::list;template <typename T>void printElements(T c){ typename T::iterator it; for(it = c.begin(); it != c.end(); ++it){ cout << *it << " "; } cout << endl;}int main(){ vector<int> vecSrc = {1, 2, 3}; list<int> listDest; copy(vecSrc.begin(), vecSrc.end(),std::back_insert_iterator<list<int> >(listDest)); //尾插法 printElements(listDest); //1 2 3 copy(vecSrc.begin(), vecSrc.end(),std::front_insert_iterator<list<int> >(listDest)); //頭插法 printElements(listDest); // 3 2 1 1 2 3 copy(vecSrc.begin(), vecSrc.end(),std::insert_iterator<list<int> >(listDest, ++listDest.begin())); //指定一個具體的位置。在第二個位置 printElements(listDest); //3 1 2 3 2 1 1 2 3 return 0;}
四、函式介面卡 繫結器 band1st //已過時band2nd //已過時band //上面兩個在c++11已經過時。由band代替。std::band的返回值就是一個函式物件。繫結的引數的個數不受限制;對於不事先繫結的引數,需要傳std::placeholders進去,從_1開始,依次遞增 例1:對自由函式進行繫結#include <iostream>#include <functional> //band函式的標頭檔案 using std::cout;using std::endl;int func(int x, int y){ return x + y;}int main(void){ using namespace std::placeholders; //這樣下面就不用寫:std::placeholders::_1了。 auto f = std::bind(func, 10); //錯誤。要寫上佔位符。 cout << f(20) << endl; auto f1 = std::bind(func, 10, _1); //func表示繫結到函式func。_1是佔位符。佔位符有兩層含義。第一層含義是,本身 的位置表示在函式中形參的位置:這裡_1在(func,10,_1)中是第2個引數,所以佔著int func(int x,int y); 的第二個引數的位置。而10就會傳給x。第二層含義是,_1表示第一 個實參,所以下面f1(20)的20會傳給_1.綜上,當呼叫f1(20)時,會執行func(10,20)函式。 cout << f1(20) << endl; //f1是一個函式物件。 return 0;}例2:對成員函式也可以繫結#include <iostream>#include <functional> using std::cout;using std::endl;int func(int x, int y){ return x + y;}struct A{ A(){ cout << "A()" << endl; } A(const A & rhs){ //拷貝建構函式 cout << "A(const A&)" << endl; } int func(int x, int y){ cout << "A::func(int,int)" << endl; cout << " x = " << x << endl; cout << " y = " << y << endl; return x + y; }};int main(void){ using namespace std::placeholders; A a; auto f2 = std::bind(&A::func, a, _2, _1); //bind的形參的繫結以值傳遞的形式進行的。繫結到類的成員函式func,注意寫法。 第二個引數把物件傳過去。後面_1和_2才是兩個引數。//bind的形參的繫結以值傳遞的形式進行的。a會以值傳遞的形式繫結到func,所以要 先根據a,執行拷貝建構函式,建立一個物件。所以這裡可以使用&a,這樣就不會再創 建新的物件了。 cout << f2(1, 2) << endl; //會執行成員函式。func(2,1) 。形參的第一個位置是第二個實參。形參的第二個位置是第一個實參。 return 0;}例3:#include <iostream>#include <functional> using std::cout;using std::endl;void f(int n1, int n2, int n3, const int & n4, int n5){ cout << "(" << n1<< "," << n2<< "," << n3<< "," << n4<< "," << n5<< ")" << endl;}int main(void){ using namespace std::placeholders; int n = 7; auto f1 = std::bind(f, _2, _1, 42, std::cref(n), n); //繫結函式f。第一個形參是第二個實參,第二個形參是第一個實參。第三個形參是 42,第四個形參是n的引用,cref表示const reference。第五個引數將n傳過去。 n = 10; f1(1, 2, 1001, 1002, 1003); //呼叫f1之後相當於執行f( 2, 1, 42, 10, 7),第二個實參傳個第一個形參,為2;第1個實參 傳個第二個形參,為1;第三個形參傳42,第四個形參是n的引用,n變成了10,所以是10. 第五個引數繫結的是當時的n的值7. //實參呼叫時,可以傳遞多餘的引數,但是無效。這裡的1001,1002,1003都沒用。 return 0;}例4:繫結資料成員的值#include <iostream>#include <functional> using std::cout;using std::endl;struct Foo{ int data = 10; //直接初始化,這是C++11新特性。不建議這麼寫。};int main(void){ using namespace std::placeholders; Foo foo; foo.data = 12; auto f3 = std::bind(&Foo::data, _1); //繫結資料成員。 cout << f3(foo) << endl; //12。傳的是物件。 return 0;}成員函式介面卡 mem_fun() //已過時mem_fun_ref() //已過時 mem_fn() //上面兩個在c++11已經過時。
四、函式介面卡 繫結器 band1st //已過時band2nd //已過時band //上面兩個在c++11已經過時。由band代替。std::band的返回值就是一個函式物件。繫結的引數的個數不受限制;對於不事先繫結的引數,需要傳std::placeholders進去,從_1開始,依次遞增 例1:對自由函式進行繫結#include <iostream>#include <functional> //band函式的標頭檔案 using std::cout;using std::endl;int func(int x, int y){ return x + y;}int main(void){ using namespace std::placeholders; //這樣下面就不用寫:std::placeholders::_1了。 auto f = std::bind(func, 10); //錯誤。要寫上佔位符。 cout << f(20) << endl; auto f1 = std::bind(func, 10, _1); //func表示繫結到函式func。_1是佔位符。佔位符有兩層含義。第一層含義是,本身 的位置表示在函式中形參的位置:這裡_1在(func,10,_1)中是第2個引數,所以佔著int func(int x,int y); 的第二個引數的位置。而10就會傳給x。第二層含義是,_1表示第一 個實參,所以下面f1(20)的20會傳給_1.綜上,當呼叫f1(20)時,會執行func(10,20)函式。 cout << f1(20) << endl; //f1是一個函式物件。 return 0;}例2:對成員函式也可以繫結#include <iostream>#include <functional> using std::cout;using std::endl;int func(int x, int y){ return x + y;}struct A{ A(){ cout << "A()" << endl; } A(const A & rhs){ //拷貝建構函式 cout << "A(const A&)" << endl; } int func(int x, int y){ cout << "A::func(int,int)" << endl; cout << " x = " << x << endl; cout << " y = " << y << endl; return x + y; }};int main(void){ using namespace std::placeholders; A a; auto f2 = std::bind(&A::func, a, _2, _1); //bind的形參的繫結以值傳遞的形式進行的。繫結到類的成員函式func,注意寫法。 第二個引數把物件傳過去。後面_1和_2才是兩個引數。//bind的形參的繫結以值傳遞的形式進行的。a會以值傳遞的形式繫結到func,所以要 先根據a,執行拷貝建構函式,建立一個物件。所以這裡可以使用&a,這樣就不會再創 建新的物件了。 cout << f2(1, 2) << endl; //會執行成員函式。func(2,1) 。形參的第一個位置是第二個實參。形參的第二個位置是第一個實參。 return 0;}例3:#include <iostream>#include <functional> using std::cout;using std::endl;void f(int n1, int n2, int n3, const int & n4, int n5){ cout << "(" << n1<< "," << n2<< "," << n3<< "," << n4<< "," << n5<< ")" << endl;}int main(void){ using namespace std::placeholders; int n = 7; auto f1 = std::bind(f, _2, _1, 42, std::cref(n), n); //繫結函式f。第一個形參是第二個實參,第二個形參是第一個實參。第三個形參是 42,第四個形參是n的引用,cref表示const reference。第五個引數將n傳過去。 n = 10; f1(1, 2, 1001, 1002, 1003); //呼叫f1之後相當於執行f( 2, 1, 42, 10, 7),第二個實參傳個第一個形參,為2;第1個實參 傳個第二個形參,為1;第三個形參傳42,第四個形參是n的引用,n變成了10,所以是10. 第五個引數繫結的是當時的n的值7. //實參呼叫時,可以傳遞多餘的引數,但是無效。這裡的1001,1002,1003都沒用。 return 0;}例4:繫結資料成員的值#include <iostream>#include <functional> using std::cout;using std::endl;struct Foo{ int data = 10; //直接初始化,這是C++11新特性。不建議這麼寫。};int main(void){ using namespace std::placeholders; Foo foo; foo.data = 12; auto f3 = std::bind(&Foo::data, _1); //繫結資料成員。 cout << f3(foo) << endl; //12。傳的是物件。 return 0;}成員函式介面卡 mem_fun() //已過時mem_fun_ref() //已過時 mem_fn() //上面兩個在c++11已經過時。