91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

STL組件之算法的示例分析

發布時間:2021-12-03 11:38:49 來源:億速云 閱讀:163 作者:小新 欄目:編程語言

這篇文章主要介紹了STL組件之算法的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

STL提供了大量的模板類和函數,可以在OOP和常規編程中使用。所有的STL的大約50個算法都是完全通用的,而且不依賴于任何特定的數據類型。下面的小節說明了三個基本的STL組件:

1)迭代器提供了訪問容器中對象的方法。例如,可以使用一對迭代器指定list或vector中的一定范圍的對象。迭代器就如同一個指針。事實上,C++的指針也是一種迭代器。但是,迭代器也可以是那些定義了operator*()以及其他類似于指針的操作符地方法的類對象。

2)容器是一種數據結構,如list,vector,和deques ,以模板類的方法提供。為了訪問容器中的數據,可以使用由容器類輸出的迭代器。

3)算法是用來操作容器中的數據的模板函數。例如,STL用sort()來對一個vector中的數據進行排序,用find()來搜索一個list中的對象。函數本身與他們操作的數據的結構和類型無關,因此他們可以在從簡單數組到高度復雜容器的任何數據結構上使用。

函數和函數對象

STL中,函數被稱為算法,也就是說它們和標準C庫函數相比,它們更為通用。STL算法通過重載operator()函數實現為模板類或模板函數。這些類用于創建函數對象,對容器中的數據進行各種各樣的操作。下面的幾節解釋如何使用函數和函數對象。

函數和斷言

經常需要對容器中的數據進行用戶自定義的操作。例如,你可能希望遍歷一個容器中所有對象的STL算法能夠回調自己的函數。例如

#include <iostream.h>  #include <stdlib.h> // Need random(), srandom()  #include <time.h> // Need time()  #include <vector> // Need vector  #include <algorithm> // Need for_each()   #define VSIZE 24 // Size of vector  vector<long> v(VSIZE); // Vector object   // Function prototypes  void initialize(long &ri);  void show(const long &ri);  bool isMinus(const long &ri); // Predicate function   int main()  {  srandom( time(NULL) ); // Seed random generator   for_each(v.begin(), v.end(), initialize);//調用普通函數  cout << "Vector of signed long integers" << endl;  for_each(v.begin(), v.end(), show);  cout << endl;   // Use predicate function to count negative values  //  int count = 0;  vector<long>::iterator p;  p = find_if(v.begin(), v.end(), isMinus);//調用斷言函數  while (p != v.end()) {  count++;  p = find_if(p + 1, v.end(), isMinus);  }  cout << "Number of values: " << VSIZE << endl;  cout << "Negative values : " << count << endl;   return 0;  }   // Set ri to a signed integer value  void initialize(long &ri)  {  ri = ( random() - (RAND_MAX / 2) );  // ri = random();  }   // Display value of ri  void show(const long &ri)  {  cout << ri << " ";  }   // Returns true if ri is less than 0  bool isMinus(const long &ri)  {  return (ri < 0);  }

所謂斷言函數,就是返回bool值的函數。

函數對象

除了給STL算法傳遞一個回調函數,你還可能需要傳遞一個類對象以便執行更復雜的操作。這樣的一個對象就叫做函數對象。實際上函數對象就是一個類,但它和回調函數一樣可以被回調。例如,在函數對象每次被for_each()或find_if()函數調用時可以保留統計信息。函數對象是通過重載 operator()()實現的。如果TanyClass定義了opeator()(),那么就可以這么使用:

TAnyClass object; // Construct object  object(); // Calls TAnyClass::operator()() function  for_each(v.begin(), v.end(), object);

STL定義了幾個函數對象。由于它們是模板,所以能夠用于任何類型,包括C/C++固有的數據類型,如long。有些函數對象從名字中就可以看出它的用途,如plus()和multiplies()。類似的greater()和less-equal()用于比較兩個值。

注意

有些版本的ANSI C++定義了times()函數對象,而GNU C++把它命名為multiplies()。使用時必須包含頭文件<functional>。

一個有用的函數對象的應用是accumulate() 算法。該函數計算容器中所有值的總和。記住這樣的值不一定是簡單的類型,通過重載operator+(),也可以是類對象。

Listing 8. accum.cpp

#include <iostream.h>  #include <numeric> // Need accumulate()  #include <vector> // Need vector  #include <functional> // Need multiplies() (or times())  #define MAX 10  vector<long> v(MAX); // Vector object  int main()  {  // Fill vector using conventional loop  //  for (int i = 0; i < MAX; i++)  v[i] = i + 1;  // Accumulate the sum of contained values  //  long sum =  accumulate(v.begin(), v.end(), 0);  cout << "Sum of values == " << sum << endl;  // Accumulate the product of contained values  //  long product =  accumulate(v.begin(), v.end(), 1, multiplies<long>());//注意這行  cout << "Product of values == " << product << endl;  return 0;  }

編譯輸出如下:

$ g++ accum.cpp  $ ./a.out  Sum of values == 55  Product of values == 3628800

『注意使用了函數對象的accumulate()的用法。accumulate() 在內部將每個容器中的對象和第三個參數作為multiplies函數對象的參數,multiplies(1,v)計算乘積。VC中的這些模板的源代碼如下:

// TEMPLATE FUNCTION accumulate  template<class _II, class _Ty> inline _Ty accumulate(_II _F, _II _L, _Ty _V)  {for (; _F != _L; ++_F)  _V = _V + *_F;  return (_V); }  // TEMPLATE FUNCTION accumulate WITH BINOP  template<class _II, class _Ty, class _Bop> inline _Ty accumulate(_II _F, _II _L, _Ty _V, _Bop _B)  {for (; _F != _L; ++_F)  _V = _B(_V, *_F);  return (_V); }  // TEMPLATE STRUCT binary_function  template<class _A1, class _A2, class _R>  struct binary_function {  typedef _A1 first_argument_type;  typedef _A2 second_argument_type;  typedef _R result_type;  };  // TEMPLATE STRUCT multiplies  template<class _Ty>  struct multiplies : binary_function<_Ty, _Ty, _Ty> {  _Ty operator()(const _Ty& _X, const _Ty& _Y) const {return (_X * _Y); }  };

引言:如果你想深入了解STL到底是怎么實現的,***的辦法是寫個簡單的程序,將程序中涉及到的模板源碼給copy下來,稍作整理,就能看懂了。所以沒有必要去買什么《STL源碼剖析》之類的書籍,那些書可能反而浪費時間。』

(1)發生器函數對象

有一類有用的函數對象是“發生器”(generator)。這類函數有自己的內存,也就是說它能夠從先前的調用中記住一個值。例如隨機數發生器函數。

普通的C程序員使用靜態或全局變量 “記憶”上次調用的結果。但這樣做的缺點是該函數無法和它的數據相分離『還有個缺點是要用TLS才能線程安全』。顯然,使用類來封裝一塊:“內存”更安全可靠。先看一下例子:

Listing 9. randfunc.cpp

#include <iostream.h>  #include <stdlib.h> // Need random(), srandom()  #include <time.h> // Need time()  #include <algorithm> // Need random_shuffle()  #include <vector> // Need vector  #include <functional> // Need ptr_fun()  using namespace std;  // Data to randomize  int iarray[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};  vector<int> v(iarray, iarray + 10);  // Function prototypes  void Display(vector<int>& vr, const char *s);  unsigned int RandInt(const unsigned int n);  int main()  {  srandom( time(NULL) ); // Seed random generator  Display(v, "Before shuffle:");  pinter_to_unary_function<unsigned int, unsigned int>  ptr_RandInt = ptr_fun(RandInt); // Pointer to RandInt()//注意這行  random_shuffle(v.begin(), v.end(), ptr_RandInt);  Display(v, "After shuffle:");  return 0;  }  // Display contents of vector vr  void Display(vector<int>& vr, const char *s)  {  cout << endl << s << endl;  copy(vr.begin(), vr.end(), ostream_iterator<int>(cout, " "));  cout << endl;  }  // Return next random value in sequence modulo n  unsigned int RandInt(const unsigned int n)  {  return random() % n;  }

編譯運行結果如下:

$ g++ randfunc.cpp  $ ./a.out  Before shuffle:  1 2 3 4 5 6 7 8 9 10  After shuffle:  6 7 2 8 3 5 10 1 9 4

首先用下面的語句申明一個對象:

pointer_to_unary_function<unsigned int, unsigned int>  ptr_RandInt = ptr_fun(RandInt);

這兒使用STL的單目函數模板定義了一個變量ptr_RandInt,并將地址初始化到我們的函數RandInt()。單目函數接受一個參數,并返回一個值。現在random_shuffle()可以如下調用:

random_shuffle(v.begin(), v.end(), ptr_RandInt);

在本例子中,發生器只是簡單的調用rand()函數。

關于常量引用的一點小麻煩(不翻譯了,VC下將例子中的const去掉)

(2)發生器函數類對象

下面的例子說明發生器函數類對象的使用。

Listing 10. fiborand.cpp

#include <iostream.h>  #include <algorithm> // Need random_shuffle()  #include <vector> // Need vector  #include <functional> // Need unary_function  using namespace std;  // Data to randomize  int iarray[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};  vector<int> v(iarray, iarray + 10);  // Function prototype  void Display(vector<int>& vr, const char *s);  // The FiboRand template function-object class  template <class Arg>  class FiboRand : public unary_function<Arg, Arg> {  int i, j;  Arg sequence[18];  public:  FiboRand();  Arg operator()(const Arg& arg);  };  void main()  {  FiboRand<int> fibogen; // Construct generator object  cout << "Fibonacci random number generator" << endl;  cout << "using random_shuffle and a function object" << endl;  Display(v, "Before shuffle:");  random_shuffle(v.begin(), v.end(), fibogen);  Display(v, "After shuffle:");  }  // Display contents of vector vr  void Display(vector<int>& vr, const char *s)  {  cout << endl << s << endl;  copy(vr.begin(), vr.end(),  ostream_iterator<int>(cout, " "));  cout << endl;  }  // FiboRand class constructor  template<class Arg>  FiboRand<Arg>::FiboRand()  {  sequence[17] = 1;  sequence[16] = 2;  for (int n = 15; n > 0; n&mdash;)  sequence[n] = sequence[n + 1] + sequence[n + 2];  i = 17;  j = 5;  }  // FiboRand class function operator  template<class Arg>  Arg FiboRand<Arg>::operator()(const Arg& arg)  {  Arg k = sequence[i] + sequence[j];  sequence[i] = k;  i--;  j--;  if (i == 0) i = 17;  if (j == 0) j = 17;  return k % arg;  }

編譯運行輸出如下:

$ g++ fiborand.cpp  $ ./a.out  Fibonacci random number generator  using random_shuffle and a function object  Before shuffle:  1 2 3 4 5 6 7 8 9 10  After shuffle:  6 8 5 4 3 7 10 1 9

該程序用完全不通的方法使用使用rand_shuffle。Fibonacci 發生器封裝在一個類中,該類能從先前的“使用”中記憶運行結果。在本例中,類FiboRand 維護了一個數組和兩個索引變量I和j。

FiboRand類繼承自unary_function() 模板:

template <class Arg>  class FiboRand : public unary_function<Arg, Arg> {...

Arg是用戶自定義數據類型。該類還定以了兩個成員函數,一個是構造函數,另一個是operator()()函數,該操作符允許random_shuffle()算法象一個函數一樣“調用”一個FiboRand對象。

(3)綁定器函數對象

一個綁定器使用另一個函數對象f()和參數值V創建一個函數對象。被綁定函數對象必須為雙目函數,也就是說有兩個參數,A和B。STL 中的幫定器有:

  • bind1st() 創建一個函數對象,該函數對象將值V作為***個參數A。

  • bind2nd()創建一個函數對象,該函數對象將值V作為第二個參數B。

舉例如下:

Listing 11. binder.cpp

#include <iostream.h>  #include <algorithm>  #include <functional>  #include <list>  using namespace std;  // Data  int iarray[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};  list<int> aList(iarray, iarray + 10);  int main()  {  int k = 0;  count_if(aList.begin(), aList.end(),  bind1st(greater<int>(), 8), k);  cout << "Number elements < 8 == " << k << endl;  return 0;  }

Algorithm count_if()計算滿足特定條件的元素的數目。 這是通過將一個函數對象和一個參數捆綁到為一個對象,并將該對象作為算法的第三個參數實現的。 注意這個表達式:

bind1st(greater<int>(), 8)

該表達式將greater<int>()和一個參數值8捆綁為一個函數對象。由于使用了bind1st(),所以該函數相當于計算下述表達式:

8 > q

表達式中的q是容器中的對象。因此,完整的表達式

count_if(aList.begin(), aList.end(),  bind1st(greater<int>(), 8), k);

計算所有小于或等于8的對象的數目。

(4)否定函數對象

所謂否定(negator)函數對象,就是它從另一個函數對象創建而來,如果原先的函數返回真,則否定函數對象返回假。有兩個否定函數對象:not1()和 not2()。not1()接受單目函數對象,not2()接受雙目函數對象。否定函數對象通常和幫定器一起使用。例如,上節中用bind1nd來搜索 q<=8的值:

count_if(aList.begin(), aList.end(),  bind1st(greater<int>(), 8), k);

如果要搜索q>8的對象,則用bind2st。而現在可以這樣寫:

start = find_if(aList.begin(), aList.end(),  not1(bind1nd(greater<int>(), 6)));

你必須使用not1,因為bind1nd返回單目函數。

總結:使用標準模板庫 (STL)

盡管很多程序員仍然在使用標準C函數,但是這就好像騎著毛驢尋找Mercedes一樣。你當然最終也會到達目標,但是你浪費了很多時間。

盡管有時候使用標準C函數確實方便(如使用sprintf()進行格式化輸出)。但是C函數不使用異常機制來報告錯誤,也不適合處理新的數據類型。而且標準C函數經常使用內存分配技術,沒有經驗的程序員很容易寫出bug來。.

C++標準庫則提供了更為安全,更為靈活的數據集處理方式。STL最初由HP實驗室的Alexander Stepanov和Meng Lee開發。最近,C++標準委員會采納了STL,盡管在不同的實現之間仍有細節差別。

STL的最主要的兩個特點:數據結構和算法的分離,非面向對象本質。訪問對象是通過象指針一樣的迭代器實現的;容器是象鏈表,矢量之類的數據結構,并按模板方式提供;算法是函數模板,用于操作容器中的數據。由于STL以模板為基礎,所以能用于任何數據類型和結構。

感謝你能夠認真閱讀完這篇文章,希望小編分享的“STL組件之算法的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

stl
AI

女性| 浪卡子县| 铅山县| 丹寨县| 新竹市| 杭锦旗| 平谷区| 商洛市| 上蔡县| 若羌县| 红安县| 黎城县| 长沙县| 康定县| 阳原县| 鄄城县| 营山县| 武乡县| 涿鹿县| 彩票| 平定县| 建湖县| 丹江口市| 綦江县| 崇州市| 郁南县| 德化县| 滕州市| 泗洪县| 牙克石市| 大同县| 容城县| 江城| 古蔺县| 弋阳县| 瓦房店市| 侯马市| 自治县| 水城县| 高唐县| 咸阳市|