C++primer 第十章筆記 初稿

10.1概述

  1. 大多數定義在頭文件裏,部分數值泛型算法定義在裏。

  2. 算法不依賴於容器類型,但依賴於元素類型操作(即關係運算)。

  3. 對於內置數組,可以使用 begin(數組名)、end(數組名)來獲取對應指針,使算法對內置數組進行類似容器的處理。

  4. 算法並不真正執行容器本身操作,一切操作都基於迭代器。

10.2簡單泛型算法的使用

  1. 只讀算法

    • count

      • 接收:一對迭代器和一個值。
      • 返回:該值出現的次數。
    • find

      • 接收:一對迭代器和一個值。
      • 返回:迭代器。
    • accumulate

      • 接收:一對迭代器和一個初值。
      • 返回:累加求和結果。
      • 誤區:string可以實現,但const char* 不可以實現。
    • equal

      • 接收:第一個序列的一對迭代器和第二個序列的首迭代器。
      • 返回:true/false。
      • 誤區:string可以實現,但const char* 不可以實現。
  2. 寫算法

    • fill

      • 接收:一對迭代器和一個用於賦值的值。
    • fill_n

      • 接收:一個迭代器表示開始位置,一個值表示賦值個數,一個值用於賦值。
      • 誤區:不能給空容器賦值。
    • back_inserter

      • 頭文件:iterator
      • 功能:向容器末尾插入元素(結合fill_n可解決空容器問題)。
      • 例子
        vector<int>vec;
        auto it=back_inserter(vec);
        fill_n(it,10,0);
  3. 重排算法
    • unique
      • 接收:一對迭代器。
      • 返回:指向重排後不重複區域後一個位置的迭代器。
      • 和erase方法配套可以去重。

10.3 自定義操作

  1. 謂詞:一個可調用的表達式,返回結果爲一個能用作條件的值,分一元謂詞與二元謂詞(也就是自定義取代默認操作符)。

  2. 可調用對象

    • 定義:可以對其使用調用運算符(())的對象或表達式。
    • 包括:函數與函數指針、重載函數調用運算符的類、lambda表達式。
  3. lambda表達式

    • 定義:可調用的代碼單元,類似於未命名的內聯函數,格式爲:
      [capture list](parameter list)>return type {function body}
    • 特點:
      • 可定義在函數內部。
      • 必須使用尾置返回,但返回類型與參數列表可忽略,同時自動推斷返回類型(若包含單一return之外的語句則返回void)。
      • 不能有默認參數。
    • 例子

      auto f = [](const string &a, const string &b)
          {return a.size() < b.size();};
      stable_sort(s.begin(), s.end(), f());

      或者直接

      stable_sort(s.begin(), s.end(),
                  [](const string &a, const string &b)
                  {return a.size() < b.size();});
    • 捕獲方式:

      • 顯示捕獲
        • 值捕獲
          • 如果想在lambda表達式中改變該值,須在參數列表後,表達式體前加關鍵字 mutable。
        • 引用捕獲
      • 隱式捕獲:只寫明捕獲方式而不寫明捕獲的具體對象。
  4. 函數替代lambda表達式

    • 思路:運用bind函數

    • bind函數

      • 頭文件:functional
      • 一般形式:
        auto newCallable=bind(callable, arg_list)

        其中callable爲相關函數,arg_list爲逗號分隔的 參數列表。
    • arg_list
      • _n:佔位符,表示綁定函數的第n個參數。
      • 通常爲_n與實參混合使用。
      • 其中_n必須顯示聲明using namespace std::placeholders。
      • 一個巧妙運用

        sort(words.begin(), words.end(), bind(isShorter, _2, _1));
      • 運用ref()函數綁定參數實現引用傳遞。

10.4 頭文件中的迭代器

  1. 插入迭代器:back_inserter、front_inserter、inserter。

  2. IO迭代器:

    • istream_iterator

      • 如果綁定流則從流的第一個位置開始,不綁定則爲尾後位置。
      • 輔助創建容器

        istream_iterator<int>in(cin),eof;
        vector<int>v(in,eof);
      • 迭代器被解引用時才真正從流中讀取數據。

    • ostream_iterator

      • 通過綁定的可以爲每次輸出附加一個固定輸出。
      • 輔助容器輸出(推薦未註釋的方法)
            for(auto e : v)
                out = e;
        //  for(auto e : v)
        //      *out++ = e;
        //  copy(v.begin(), v.end(), out); 
  3. 反向迭代器
    會出現倒序輸出的情況(有時來說是個問題),可以使用base()方法使反向迭代器轉化爲普通迭代器。

10.5 泛型算法結構

  1. 五類迭代器(層次由低到高)

    • 輸入迭代器

      • 支持 ==、!=
      • 支持前置、後置自增
      • 支持解引用*與->運算符
      • 只能用於單遍掃描,可支持算法find、accumulate,istream_iterator是輸入迭代器。
    • 輸出迭代器

      • 輸入迭代器的補集
      • 支持前置、後置自增
      • 支持解引用運算符
      • 出現在賦值運算符的左側
      • 支持copy的第三個參數,ostream_iterator是輸出迭代器
    • 前向迭代器
      • 輸入輸出迭代器的並集
      • 支持replace算法,forward_list的迭代器是前向迭代器
    • 雙向迭代器
      • 支持前置、後置自減運算符
      • 支持reverse算法
    • 隨機訪問迭代器
      • 比較運算符
      • 單迭代器的加減運算符
      • 兩個迭代器的減運算符
      • 下標運算符
      • 支持sort,array,deque,string,vector都是隨機訪問迭代器,內置數組的指針也是。
  2. 接收單個目標迭代器的算法,一般可以用輸入迭代器代替寫入目的位置的迭代器以保證安全。

  3. 算法命名規範

    • 一些算法使用重載,接收謂詞來代替==或<運算符。
    • _if版本的算法,通過謂詞來代替元素值。
    • 一些算法增加_copy版本把新的結果存儲到其他容器中
  4. 鏈表的特定算法

    • merge:分治合併(有重載的謂詞版本)
    • remove:刪除元素(有remove_if的謂詞版本)
    • reverse、sort、unique
    • splice:將一個鏈表的一部分移動到另一個鏈表中,其中若調用者爲雙向鏈表,則移動到位置之前,否則爲位置之後。
    • 鏈表特有的算法會改變底層容器。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章