STL——配接器、經常使用算法使用

學習STL,必然會用到它裏面的適配器和一些經常使用的算法。它們都是STL中的重要組成部分。ios

適配器


 

在STL裏能夠用一些容器適配獲得適配器。例如其中的stack和queue就是由雙端隊列deque容器適配而來。其實適配器也是一種設計模式,該種模式是將一個類的接口轉換成用戶但願的另一個接口。簡單的說:就是須要的東西就在眼前,但卻不能用或者使用不是很方便,而短期又沒法改造它,那咱們就經過已存在的東西去適配它。算法

STL中的適配器一共有三種:編程

①應用於容器的即容器適配器;好比stack和queue就是對deque的接口進行了轉調 ②應用於迭代器的即迭代器適配器;好比反向迭代器就是對迭代器的接口進行了轉調 ③應用於仿函數的即函數適配器

 

不過咱們日常用容器適配器用得比較多,因此咱們着重容器適配器的使用,其它適配器可參考《STL源碼剖析》。設計模式

 

(1)stack/queue數據結構

咱們都知道stack和queue都是一種特殊的線性數據結構,要求在其固定端進行數據的插入和刪除操
做。而在STL的容器當中,deque是雙開口的結構,所以STL就將它做爲棧和隊列的底層結構,而後對deque稍加改裝後就實現出來了stack和queue。編程語言

像這種:將某個類的接口進行從新包裝而實現出的新結構,稱之爲適配器函數

stack原型定義學習

經常使用接口:spa

 

queue原型定義相似:設計

 

 

 注意:因爲棧和隊列不能遍歷,因此stack queue沒有提供迭代器。

 

 

(2)priority_queue

 priority_queue(優先級隊列)是一個擁有權值關鍵的隊列,容許用戶以任意次序將元素插入容器內,但取出時每次都是取優先級最高(低)的元素,這正是heap所具備該特性,所以priority_queue以vector做爲底層存儲元素空間,將heap算法進行包裝,實現出了優先級隊列 。

定義原型:

注:它的頭文件包含在#include <queue>中

 

關於它的使用:

1.由於僅需取隊首和隊尾元素的操做,所以 priority_queue 優先隊列容器也不提供迭代器,對其餘任意位置處的元素進行直接訪問操做。

2.調用top成員函數取隊頭元素時,因爲隊列內部封裝的堆算法,取得的元素是權值最大的元素。

3.調用pop刪除頂部的元素時, 刪除的元素是具備最高權值的元素。而且一般pop前會調用成員top進行檢索。

pop成員函數有效地調用pop_heap算法來保留priority_queues的heap屬性,而後調用基礎容器對象的成員函數pop_back來刪除該元素。

4.它一樣支持定製比較的仿函數進行自定義順序比較。

結合這些操做,咱們能夠來實現一個小功能

 

 案例:根據出現次數,統計前k項編程語言

 

 /************************************************************************
   > File Name: 1.cc
   > Author: tp
   > Mail: 
   > Created Time: Sun 20 May 2018 10:51:06 PM CST
  ************************************************************************/
 #include <iostream>
 #include <vector>
 #include <queue>
 #include <unordered_map>
 using namespace std;
 
 typedef unordered_map<string, int>::iterator UmapIte;
 struct CountCompare
 {
     bool operator( )(UmapIte lhs, UmapIte rhs )
     {
         return lhs->second > rhs->second;
     }
 };
 vector<string> GetTopKLanguage( const vector<string>& v, int k)
 {
     unordered_map<string, int> umap;
     //將每種語言次數對應統計起來
     for(  int i=0; i< v.size(  ) ; ++i)
     {
         umap[ v[ i] ] ++;
     }
     UmapIte it1 = umap.begin(  ) ;
     while(  it1 != umap.end(  ) )
     {
         cout<<it1->first<<"  :" <<it1->second<<endl;
         ++it1;
     }
     //用priority_queue對pair<string, int>按權值排序
     priority_queue<string, vector<UmapIte>, CountCompare> pq;
     UmapIte it = umap.begin(  ) ;
     int m = k;
     while(  it != umap.end(  ) )
     {
         if( m > 0 && m--)
             pq.push( it) ;
         else
         {
             //取到當前隊列中權值最大(值最小)的元素來pop,
             //至關於逐漸把出現次數較少的語言彈出,將出現次數較多的留下。
             UmapIte top = pq.top(  ) ;
             if(  it->second > top->second)
             {
                 pq.pop( ) ;
                 pq.push( it) ;
             }
         }
         ++it;
     }
     cout<<endl;
     while( !pq.empty(  )  )
     {
         cout<<pq.top(  ) ->first<<"  :" <<pq.top(  ) ->second<<endl;
         pq.pop(  ) ;
     }
     //  vector<string> ret;
     //  for(  int i=0; i<k; ++i) 
     //  {  
     //      ret.push_back( pq.top( ) ->first) ;
     //      pq.pop( ) ;
     //  } 
     //  return ret;
 }
 
 int main(  )
 {
     vector<string> v;
     v.push_back( " PHP" ) ;
     v.push_back( " Python" ) ;
     v.push_back( " Python" ) ;
     v.push_back( " Java" ) ;
     v.push_back( " PHP" ) ;
     v.push_back( " C/C++" ) ;
     v.push_back( " C/C++" ) ;
     v.push_back( " C/C++" ) ;
     v.push_back( " PHP" ) ;
     v.push_back( " Java" ) ;
     v.push_back( " PHP" ) ;
     v.push_back( " Go" ) ;
     v.push_back( " PHP" ) ;
     v.push_back( " Java" ) ;
     v.push_back( " PHP" ) ;
     v.push_back( " PHP" ) ;
     v.push_back( " PHP" ) ;
 
     GetTopKLanguage( v, 3) ;
 
     return 0;
 } 

 

 這裏要統計出現次數前3的語言(其中因爲優先級隊列遍歷的特殊性,世上最好的語言最後出現):

 

 

經常使用算法


 STL中的算法是將經常使用的算法規範出來,它做用的元素範圍是能夠經過迭代器或指針訪問的任何對象序列;但算法只關心操做的步驟,與數據的結構沒有任何的關係(即它不會影響容器的結構 如大小或存儲分配),並且STL在設計時就有一個目標,就是算法可複用,效率要儘量的高。STL中收錄了極具複用價值的70多個算法,包括:排序,查找,排列組合,數據移動,拷貝,刪除,比較組合,運算等

 

關於它的用法:

首先要包含頭文件<algorithm>,裏面定義了各類的算法的函數集合。

常見算法:

 查找類算法
 find/find_if/find_first_of/binary_search/count/count_if

 排序和通用算法
sort/stable_sort/partial_sort/partial_sum/partition/merge/reverse

 刪除和替換算法
 copy/copy_backward/remove/remove_if/swap/unique

排列組合算法
prev_permutation/next_permutation

 集合操做
set_difference/set_union/set_intersection

 簡單應用

1.查找

//binary_search
 void test_binary_search( ) { int a[ ] = {11,2,4,5,9,0,3,6}; vector<int> v(a, a+ 8); sort(v.begin( ), v.end( )); cout<<binary_search(v.begin( ), v.end( ), 6); //結果 1
 }

 

2.排序

//partiton
 bool IsBigerK(int curValue) { return curValue < 3; } void test_partition( ) { vector<int> a; a.push_back(6); a.push_back(5); a.push_back(4); a.push_back(3); a.push_back(2); a.push_back(1); //以3爲邊界劃分  partition(a.begin( ), a.end( ), IsBigerK); for( int i=0; i< a.size(); ++i) cout<<a[ i]<<" "; cout<<endl; //結果:1 2 4 3 5 6
 } //sort //template<class T> //形如這樣自定義來比較 //struct Greater //{ // bool operator()(const T& l, const T& r) // { // return l > r; // } //};
 void test_sort( ) { vector<int> v; v.push_back(1); v.push_back(3); v.push_back(4); v.push_back(0); v.push_back(10); v.push_back(3); sort(v.begin( ), v.end(), greater<int>()); for( int i=0; i< v.size( ); ++i) cout<<v[i]<<" "; cout<<endl; //結果: //10 4 3 3 1 0
 }

3.排列組合問題

 //排列問題 //next_permutation 求得下一個排列
 void test_permutation( ) { string str("abc"); do { cout<<str.c_str( )<<endl; }while(next_permutation(str.begin( ), str.end( ))); //結果: //abc //acb //bac //bca //cab //cba //注意:對於值重複,不形成影響. aab求得的全排列不會用重複
 }

 

 

4.集合操做

set_difference

關於使用:

1. 在兩個集合中找出不一樣的元素,這些不一樣的元素所有來自與第一組中,不從第二組中來。

2.它的返回值爲一個迭代器it,迭代器指向存儲的結果(即找出來的不一樣元素)最後一個位置。一般 用it-ret.begin()獲得不一樣元素的個數。

 void test_set_difference( ) { int a[ ] = {1, 4, -1, 5, 2}; int b[ ] = {3, 4, 1, 5, 6}; //+5 注意! sort(a, a+5); //-1 1 2 4 5 sort(b, b+5); //1 3 4 5 6  vector<int> v(10); vector<int>::iterator it; it =set_difference(a, a+5, b, b+5, v.begin()) ;//it是-1 2 0 0 0 0 0 0 0 0 的結尾 v.resize(it-v.begin()); //-1 2 it = v.begin( ); while( it != v.end( )) { cout<<*it<<" "; ++it; } //結果:-1 2 }

 

 

 算法當中的相關分類總覽:

參考:http://www.cplusplus.com/reference/algorithm/

相關文章
相關標籤/搜索