1. 程式人生 > 實用技巧 >"C++ Primer" 讀書筆記 第十一章 泛型演算法

"C++ Primer" 讀書筆記 第十一章 泛型演算法

  首先我們注意一下第十章 關聯容器中有哪些需要注意的:

  • 順序容器是通過元素在容器中的位置訪問的,而關聯容器則是通過元素的鍵 (key)進行訪問的
  • pair型別是一種模板型別,型別形參為資料成員的型別
  • map容器的每一個鍵值對是一個pair型別。pair型別是一種標準庫型別,但是其成員first和second卻是public的
  • 關聯容器沒有pop/push等操作,也無法通過vector<char>('a',5);這種方式定義
  • 鍵的型別必須定義 < 操作符,預設情況下將作為比較函式。這個比較函式必須在鍵型別上支援嚴格弱排序
  • 因此不支援 < 操作符的型別將不能作為 鍵
  • 對map的迭代器進行解引用將得到鍵值對,是一個pair型別的物件;而下標返回的是mapped_type, 值的型別
  • 用下標訪問map中不存在的元素將自動地新增一個新的元素,且值被初始化為預設值(int就初始化為0)  
  • count函式檢測是否存在某個鍵;find函式返回指向目標鍵的迭代器,如果元素不存在,則返回end
  • earse函式實現刪除元素,可以取 鍵(返回刪除的元素個數 0或1);可以取迭代器或迭代器範圍(返回void)

 泛型演算法

  泛型演算法可以作用在不同型別的容器和不同型別的元素上。當然也可以作用在內建陣列型別上。

  標準容器定義的操作其實很少,主要是:元素的新增和刪除、訪問首尾元素、獲取容器的大小、獲取begin()和end()迭代器。

  一般使用演算法都要給定迭代器範圍。演算法不依賴容器的操作,而完全通過迭代器解決四個問題:

  1. 遍歷集合的方式:通過迭代器自增實現遍歷容器中所有元素

  2. 演算法應用的範圍在何處終止:通過超出末端一位的哨兵迭代器

  3. 是否找到某個元素或是否通過演算法達成某種效果:通過是否到達end體現

  4. 元素間如何進行比較,== 操作符 < 操作符等,或者自行定義的比較函式

  • 演算法不會改變容器的大小:實際上演算法不會插入或者刪除元素,而是改變元素值或者移動位置
  • 利用accumulate函式可以方便地將vector中所有的string連線為大的string,accumulate函式的第三個引數是必須的,作為起始值的同時也指定了以何種方式對迭代器解引用的值進行解釋!
  • 累加和的型別與起始值的型別相同,因此string型別相加不能用字串字面值const * char作為起始值
  • 泛型演算法使得操作時型別是否匹配沒那麼重要:list<string>與vector<const *char>可以用find_first_of函式,因為string與char間定義了==操作符  
  • 向容器中寫入元素的演算法
    • fill(v.begin(),v.end(),0)函式, 迭代器範圍有效則寫入,如果超出則終止,因此安全
    • fill_n函式不會檢查是否有效,這種寫法不安全,因為容器本來就沒有那麼多空間儲存新元素
    • back_inserter是迭代器介面卡,確保容器有足夠的空間儲存輸出資料
    • copy函式實現元素拷貝
    • replace函式實現查詢替換:replace(li.begin(), li.end(), 0, 42)
    • replace_copy函式實現查詢替換並拷貝到另一個容器 replace_copy(li.begin(),li.end(),back_inserter(ivec),0,42)
  • 對容器元素重新排序的演算法
    • 去除重複:先呼叫sort進行排序,再呼叫unique函式實現重排序,返回一個迭代器,標記沒有重複值的範圍的下一個位置,再呼叫erase函式(注意增刪容器元素要用到容器的方法)實現刪除後面重複的元素
  • 查詢演算法 均可以在最後加func判斷函式,實現自定義“相等”  
    • find(beg,end,val)和count(beg,end,val)要求容器中的元素型別過載==操作
    • find_if(b,e,func)返回迭代器範圍中使func為true的第一個迭代器位置, count_if(b,e,func)則返回數量
    • find_first_of(b1,e1,b2,e2)返回一個第一段迭代器範圍中的某個位置,只要該位置的值在範圍二中即可
    • find_first_of(b1,e1,b2,e2,func)不用==操作,而用我們自己定義的判斷函式來定義兩個元素是否相等
    • find_end(b1,e1,b2,e2)查詢第二段範圍內的元素在第一段範圍內的最後一次出現
    • adjacent_find(b,e,func)查詢第一對相鄰且使func()函式返回true的元素,預設==  
    • search(b1,e1,b2,e2)查詢第二個子序列在第一個子序列出現的第一個位置
    • search_n(b,e,count,val)查詢指定的連續count個val的出現位置  
  • 迭代器,反向迭代器與distance()函式 
// 使用distance()函式需要#include<iterator>
string a = "hello world";
auto it1 = find(a.begin(),a.end(),'e');
distance(a.begin(), it1); // 得到1
auto it2 = find(a.rbegin(),a.rend(),'l');
distance(it2,a.rbegin());// 得到-1
distance(a.rbegin(),it2); // 得到1
// 注意反向迭代器以a.rbegin()為第一個位置;且反向迭代器用自增操作符++實際上是往左邊移動了

  注意反向迭代器與迭代器不能同時在一個演算法中使用;

  使用前向迭代器寫元素的演算法(只能用前向迭代器):

  swap(e1, e2), iter_swap(it1, it2), fill(b, e, val), generate(b, e, Gen_func), replace(b, e, old_val, new_val), replace_if(b,e,func,new_val)