成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

STL組件之算法

開發 后端 算法
我們都知道STL的三大組件是迭代器,算法和容器。本文介紹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算法能夠回調自己的函數。例如

 

  1. #include <iostream.h>  
  2. #include <stdlib.h> // Need random(), srandom()  
  3. #include <time.h> // Need time()  
  4. #include <vector> // Need vector  
  5. #include <algorithm> // Need for_each()  
  6.  
  7. #define VSIZE 24 // Size of vector  
  8. vector<long> v(VSIZE); // Vector object  
  9.  
  10. // Function prototypes  
  11. void initialize(long &ri);  
  12. void show(const long &ri);  
  13. bool isMinus(const long &ri); // Predicate function  
  14.  
  15. int main()  
  16. {  
  17. srandom( time(NULL) ); // Seed random generator  
  18.  
  19. for_each(v.begin(), v.end(), initialize);//調用普通函數  
  20. cout << "Vector of signed long integers" << endl;  
  21. for_each(v.begin(), v.end(), show);  
  22. cout << endl;  
  23.  
  24. // Use predicate function to count negative values  
  25. //  
  26. int count = 0;  
  27. vector<long>::iterator p;  
  28. p = find_if(v.begin(), v.end(), isMinus);//調用斷言函數  
  29. while (p != v.end()) {  
  30. count++;  
  31. p = find_if(p + 1, v.end(), isMinus);  
  32. }  
  33. cout << "Number of values: " << VSIZE << endl;  
  34. cout << "Negative values : " << count << endl;  
  35.  
  36. return 0;  
  37. }  
  38.  
  39. // Set ri to a signed integer value  
  40. void initialize(long &ri)  
  41. {  
  42. ri = ( random() - (RAND_MAX / 2) );  
  43. // ri = random();  
  44. }  
  45.  
  46. // Display value of ri  
  47. void show(const long &ri)  
  48. {  
  49. cout << ri << " ";  
  50. }  
  51.  
  52. // Returns true if ri is less than 0  
  53. bool isMinus(const long &ri)  
  54. {  
  55. return (ri < 0);  

 

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

函數對象

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

 

  1. TAnyClass object; // Construct object  
  2. object(); // Calls TAnyClass::operator()() function  
  3. 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

 

  1. #include <iostream.h>  
  2. #include <numeric> // Need accumulate()  
  3. #include <vector> // Need vector  
  4. #include <functional> // Need multiplies() (or times())  
  5. #define MAX 10  
  6. vector<long> v(MAX); // Vector object  
  7. int main()  
  8. {  
  9. // Fill vector using conventional loop  
  10. //  
  11. for (int i = 0; i < MAX; i++)  
  12. v[i] = i + 1;  
  13. // Accumulate the sum of contained values  
  14. //  
  15. long sum =  
  16. accumulate(v.begin(), v.end(), 0);  
  17. cout << "Sum of values == " << sum << endl;  
  18. // Accumulate the product of contained values  
  19. //  
  20. long product =  
  21. accumulate(v.begin(), v.end(), 1, multiplies<long>());//注意這行  
  22. cout << "Product of values == " << product << endl;  
  23. return 0;  

編譯輸出如下:

 

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

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

 

  1. // TEMPLATE FUNCTION accumulate  
  2. template<class _II, class _Ty> inline 
  3. _Ty accumulate(_II _F, _II _L, _Ty _V)  
  4. {for (; _F != _L; ++_F)  
  5. _V = _V + *_F;  
  6. return (_V); }  
  7. // TEMPLATE FUNCTION accumulate WITH BINOP  
  8. template<class _II, class _Ty, class _Bop> inline 
  9. _Ty accumulate(_II _F, _II _L, _Ty _V, _Bop _B)  
  10. {for (; _F != _L; ++_F)  
  11. _V = _B(_V, *_F);  
  12. return (_V); }  
  13. // TEMPLATE STRUCT binary_function  
  14. template<class _A1, class _A2, class _R>  
  15. struct binary_function {  
  16. typedef _A1 first_argument_type;  
  17. typedef _A2 second_argument_type;  
  18. typedef _R result_type;  
  19. };  
  20. // TEMPLATE STRUCT multiplies  
  21. template<class _Ty>  
  22. struct multiplies : binary_function<_Ty, _Ty, _Ty> {  
  23. _Ty operator()(const _Ty& _X, const _Ty& _Y) const 
  24. {return (_X * _Y); }  
  25. }; 

 

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

(1)發生器函數對象

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

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

Listing 9. randfunc.cpp

 

  1. #include <iostream.h>  
  2. #include <stdlib.h> // Need random(), srandom()  
  3. #include <time.h> // Need time()  
  4. #include <algorithm> // Need random_shuffle()  
  5. #include <vector> // Need vector  
  6. #include <functional> // Need ptr_fun()  
  7. using namespace std;  
  8. // Data to randomize  
  9. int iarray[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};  
  10. vector<int> v(iarray, iarray + 10);  
  11. // Function prototypes  
  12. void Display(vector<int>& vr, const char *s);  
  13. unsigned int RandInt(const unsigned int n);  
  14. int main()  
  15. {  
  16. srandom( time(NULL) ); // Seed random generator  
  17. Display(v, "Before shuffle:");  
  18. pinter_to_unary_function<unsigned int, unsigned int>  
  19. ptr_RandInt = ptr_fun(RandInt); // Pointer to RandInt()//注意這行  
  20. random_shuffle(v.begin(), v.end(), ptr_RandInt);  
  21. Display(v, "After shuffle:");  
  22. return 0;  
  23. }  
  24. // Display contents of vector vr  
  25. void Display(vector<int>& vr, const char *s)  
  26. {  
  27. cout << endl << s << endl;  
  28. copy(vr.begin(), vr.end(), ostream_iterator<int>(cout, " "));  
  29. cout << endl;  
  30. }  
  31. // Return next random value in sequence modulo n  
  32. unsigned int RandInt(const unsigned int n)  
  33. {  
  34. return random() % n;  

編譯運行結果如下:

 

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

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

 

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

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

 

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

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

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

#p#

(2)發生器函數類對象

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

Listing 10. fiborand.cpp

 

  1. #include <iostream.h>  
  2. #include <algorithm> // Need random_shuffle()  
  3. #include <vector> // Need vector  
  4. #include <functional> // Need unary_function  
  5. using namespace std;  
  6. // Data to randomize  
  7. int iarray[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};  
  8. vector<int> v(iarray, iarray + 10);  
  9. // Function prototype  
  10. void Display(vector<int>& vr, const char *s);  
  11. // The FiboRand template function-object class  
  12. template <class Arg>  
  13. class FiboRand : public unary_function<Arg, Arg> {  
  14. int i, j;  
  15. Arg sequence[18];  
  16. public:  
  17. FiboRand();  
  18. Arg operator()(const Arg& arg);  
  19. };  
  20. void main()  
  21. {  
  22. FiboRand<int> fibogen; // Construct generator object  
  23. cout << "Fibonacci random number generator" << endl;  
  24. cout << "using random_shuffle and a function object" << endl;  
  25. Display(v, "Before shuffle:");  
  26. random_shuffle(v.begin(), v.end(), fibogen);  
  27. Display(v, "After shuffle:");  
  28. }  
  29. // Display contents of vector vr  
  30. void Display(vector<int>& vr, const char *s)  
  31. {  
  32. cout << endl << s << endl;  
  33. copy(vr.begin(), vr.end(),  
  34. ostream_iterator<int>(cout, " "));  
  35. cout << endl;  
  36. }  
  37. // FiboRand class constructor  
  38. template<class Arg>  
  39. FiboRand<Arg>::FiboRand()  
  40. {  
  41. sequence[17] = 1;  
  42. sequence[16] = 2;  
  43. for (int n = 15; n > 0; n—)  
  44. sequence[n] = sequence[n + 1] + sequence[n + 2];  
  45. i = 17;  
  46. j = 5;  
  47. }  
  48. // FiboRand class function operator  
  49. template<class Arg>  
  50. Arg FiboRand<Arg>::operator()(const Arg& arg)  
  51. {  
  52. Arg k = sequence[i] + sequence[j];  
  53. sequence[i] = k;  
  54. i--;  
  55. j--;  
  56. if (i == 0) i = 17;  
  57. if (j == 0) j = 17;  
  58. return k % arg;  

編譯運行輸出如下:

 

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

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

FiboRand類繼承自unary_function() 模板:

 

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

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

#p#

(3)綁定器函數對象

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

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

舉例如下:

Listing 11. binder.cpp

 

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

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

 

  1. bind1st(greater<int>(), 8) 

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

8 > q

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

 

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

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

(4)否定函數對象

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

 

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

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

 

  1. start = find_if(aList.begin(), aList.end(),  
  2. 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以模板為基礎,所以能用于任何數據類型和結構。

【編輯推薦】

  1. 檢測C++中的內存泄漏
  2. c/c++基礎 預處理指令總結
  3. 詳細介紹c++中的類對象內存模型
  4. C++基礎 詳細介紹const的用法
  5. C++初學者 const使用詳解

 

責任編輯:于鐵 來源: 互聯網
相關推薦

2011-07-13 13:56:06

STL迭代器

2024-03-04 00:15:00

C++STL算法

2011-07-13 15:07:48

STLC++

2011-07-13 14:49:31

STLC++

2011-01-18 16:32:02

Ubuntu

2023-12-10 22:00:47

STLC++編程

2021-07-09 09:12:40

STL排序算法

2021-11-01 10:21:36

鴻蒙HarmonyOS應用

2011-07-13 14:58:53

STL容器

2021-11-05 22:47:44

冒泡排序選擇插入

2021-10-14 15:14:36

鴻蒙HarmonyOS應用

2021-03-23 13:55:35

大數據算法

2011-05-07 16:07:32

復合機

2011-07-11 15:26:49

性能優化算法

2016-12-09 09:23:50

android組件Service

2011-08-01 15:57:58

2015-04-22 10:57:22

androidSwipeRefres

2022-08-03 09:58:03

跨端框架實踐

2021-02-22 21:49:33

Vue動態組件

2021-09-05 07:35:58

lifecycleAndroid組件原理
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美 日韩 中文 | 日韩一区二区三区四区五区六区 | 午夜tv免费观看 | 国产成视频在线观看 | 欧美一区二区在线观看 | 国产一区二区三区免费观看在线 | 国产黄色小视频在线观看 | 日韩第1页 | 毛片一区二区三区 | 亚洲欧美一区二区三区视频 | 国产精品99视频 | 欧美日韩视频在线播放 | 日韩在线一区二区三区 | 日本欧美视频 | 午夜成人免费视频 | 久久精品国产一区二区三区不卡 | 亚洲免费网站 | 国产精品揄拍一区二区久久国内亚洲精 | 欧美三区在线观看 | 极情综合网 | 日韩有码一区 | 国产精品伦一区二区三级视频 | 亚洲欧美一区二区三区情侣bbw | 888久久久 | 欧美国产精品一区二区三区 | 色婷婷国产精品综合在线观看 | 中国一级毛片免费 | 久久精品中文 | 欧美一区二区在线 | 99国产精品久久久久久久 | 在线国产一区二区 | 久久免费香蕉视频 | 中文字幕在线观看av | 亚洲精品一区中文字幕乱码 | 日韩精品一区二区三区中文在线 | 久久国产精品一区二区三区 | 日日av| 久久毛片 | 亚洲国产成人精品一区二区 | 在线观看av网站永久 | 国产伦精品一区二区三区精品视频 |