STL源碼剖析 基本算法 < stl_algobase.h >

注意事項 :

  • 實際使用的時候,使用的是<algorithm>這個頭文件,不是題目中的< stl_algobase.h >?

equal函數

  • 如果兩個序列在[firsLlast) 區間內相等,equal()?返 回 true.如果第二序列的元素比較多,多出來的元素不予考慮。因此,如果我們希望保證兩個序列完全相等,必須先判斷其元素個數是否相同
    int ia[9] = {0,1,2,3,4,5,6,7,8};std::vector<int> iv1(ia,ia+5);std::vector<int> iv2(ia,ia+9);if(iv1.size() == iv2.size() &&std::equal(iv1.begin(),iv1.end(),iv2.begin())){}
  • 抑或使用容器所提供的equality操作符,例如 vecl = =vec2.如果第二序列的 元素比第一序列少,這個算法內部進行迭代行為時,會超越序列的尾端,造成不可預測的結果
  • 第一版本缺省采用元素型別所提供的equality操作符來進行大小比 較,第二版本允許我們指定仿函數pred作為比較依據

?fill

  • 將 [first/ last) 內的所有元素改填新值.?

    int ia[9] = {0,1,2,3,4,5,6,7,8};std::vector<int> iv1(ia,ia+5);std::vector<int> iv2(ia,ia+9);std::fill(iv2.begin(),iv2.end(),-1);for (auto elem:iv2) {std::cout<< elem << ' ';}std::cout<< "\n";

?fill_n

  • 將[firsllast)內的前n 個元素改填新值,返回的迭代器指向被填入的最后一個元素的下一位置。

  • ?如果n 超越了容器的現有大小,會造成什么結果?例如

  • ?我們很容易就可以從源代碼知道,由于每次迭代進行的是assignment操作,是一種覆寫(overwrite)操作,所以一旦操作區間超越了容器 大小,就會造成不可預期的結果。解決辦法之一是,利用inserter ()產生一個具 有插入(insert)而非覆寫(overwrite)能力的迭代器
  • inserter( ) 可產生一個用來修飾迭代器的配接器(iterator adapter)。用法如下
int main(int argc,char* argv[]) {int ia[9] = {0,1,2};std::vector<int> iv1(ia,ia+3);std::fill(iv1.begin(),iv1.end(),-1);std::fill_n(iv1.begin(),5,7);for (auto elem:iv1) {std::cout<< elem << ' ';}std::cout<< "\n";
}
  • ?但是實際使用的時候 并沒有出現問題

?iter_swap

  • ?iter_swap( ) 是 “迭代器之valuetype派上用場的一個好例子。是的,該函數 必須知道迭代器的veluetype,才能夠據此聲明一個對象,用來暫時存放迭代器所 指對象。為此,上述源代碼特別設計了一個雙層構造,第一層調用第二層,并多出一個額外的參數value_type(a) 這么一來,第二層就有VClIue type可以用了。
  • 乍見之下你可能會對這個額外參數在調用端和接受端的型別感到訝異,調用端是value_type (a), 接受端卻是T*。只要找出value_type ()的定義瞧瞧,就一點也不奇怪了:
#include <iostream>
#include <algorithm>
#include <vector>
#include <random>
#include <functional>template<class ForwardIt>
void selection_sort(ForwardIt begin,ForwardIt end){for (ForwardIt i = begin;i!=end;++i) {std::iter_swap(i,std::min_element(i,end));}
}
int main(int argc,char* argv[]) {std::random_device rd{};std::mt19937 gen(rd());std::uniform_int_distribution<>dist(-9,9);std::vector<int>v{};std::generate_n(std::back_inserter(v),20,std::bind(dist,gen));std::cout << "Before sort:" << std::showbase;for (auto e:v) {std::cout<<e<<' ';}selection_sort(v.begin(),v.end());std::cout<<"\nAfter sort:";for (auto e:v) {std::cout << e << ' ';}}

lexicographic al_.com pare

  • 以 “字典排列方式”對兩個序列[firstlAastl)和 [first2,last2)itt行比較。比較操作針對兩序列中的對應位置上的元素進行,并持續直到(1 )某一組對應元素彼此不相等;(2 )同時到達last1?和 last2 (當兩序列的大小相同);⑶ 到 達 lastl或last2 (當 兩 序 列 的 大 小 不 同 )。
  • 第一序列以字典排列方式(lexicographically)而言不小于第二序列

  • ?第二版本允許你指定一個仿函數comp作為比較操作之用,取代元素型別所提 供 的 less-than (小 于 )操 作 符?

#include <iostream>
#include <algorithm>
#include <vector>
#include <random>int main(int argc,char* argv[]) {std::vector<char>v1{'a','b','c','d'};std::vector<char>v2{'a','b','c','d'};std::mt19937 g{std::random_device{}()};while (!std::lexicographical_compare(v1.begin(),v1.end(),v2.begin(),v2.end())){for (auto c:v1) std::cout << c << ' ';std::cout << ">= ";for (auto c:v2) std::cout << c << ' ';std::cout << "\n";std::shuffle(v1.begin(),v1.end(),g);std::shuffle(v2.begin(),v2.end(),g);}for (auto c:v1) std::cout << c << ' ';std::cout << "< ";for (auto c:v2) std::cout << c << ' ';std::cout << "\n";
}

mism atch

  • 用來平行比較兩個序列,指出兩者之間的第一個不匹配點。返回一對迭代器;分別指向兩序列中的不匹配點,如下圖。
  • 如果兩序列的所有對應元素都匹配,返回的便是兩序列各自的last迭代器。
  • 缺省情況下是以equality操作符來比較元素; 但第二版本允許用戶指定比較操作。如果第二序列的元素個數比第一序列多,多出來的元素忽略不計。如果第二序列的元素個數比第一序列少,會發生未可預期的行為。

#include <iostream>
#include <algorithm>
#include <vector>
#include <random>bool mypredicate(int i,int j){return (i==j);
}int main(int argc,char* argv[]) {std::vector<int>my_vector{};for (int i = 1; i < 6; ++i) {my_vector.emplace_back(i*10);//10 20 30 40 50 }int myints[] = {10,20,80,320,1024};std::pair<std::vector<int>::iterator,int*>mypair;mypair = std::mismatch(my_vector.begin(),my_vector.end(),myints);std::cout << "First mismatching elements: " << *mypair.first;std::cout << " and " << *mypair.second << std::endl;++mypair.first;++mypair.second;mypair = std::mismatch(mypair.first,my_vector.end(),mypair.second, mypredicate);std::cout << "Second mismatching elements: " << *mypair.first;std::cout << " and " << *mypair.second << std::endl;return 0;
}

copy----- 強化效率無所不用其極

  • 不論是對客端程序或對STL內部而言, copy() 都是一個常常被調用的函數。由 于 copy進行的是復制操作,而復制操作不外乎運用assignment operator或 copy constructor (copy算法用的是前者),但是某些元素型別擁有的是trivial assignment operator, 因此,如果能夠使用內存直接復制行為(例如C 標準函數memmove或 memcpy) , 便能夠節省大量時間。為此,SGI STL的 copy 算法用盡各種辦法,包括函數重載(function overloading) 、型別特性(type traits)、偏特 化 (partial specialization) 等編程技巧,無所不用其極地加強效率。圖 6-2表ZK整個copy() 操作的脈絡。配合稍后出現的源代碼,可收一目了然之效。

  • ?copy算法可將輸入區間[first, last)內的兀素復制到輸出區間[result, result+(last-first)) 內? 也就是說,它會執行賦值操作 *result = *first, * (result + 1) = * ( f irst + 1) , … 依 此 類 推 。 返 回 一 個 迭 代 器 : result+(last-first)= copy 對其template參數所要求的條件非常寬松。其輸入區間只需由Inputiterators構成即可,輸出區間只需由Outputiterator構成即可。
  • 這意味著你可以使用copy算法,將任何容器的任何一段區間的內容,復制到任何 容器的任何一段區間上

  • ?如果輸入區間和輸出區間完全沒有重疊,當然毫無問題,否則便需特別注意?為什么圖6-3第二種情況(可能)會產生錯誤?從稍后即將顯示的源代碼可知,copy 算法是一一進行元素的賦值操作,如果輸出區間的起點位于輸入區間內,copy算法便(可能)會在輸入區間的(某些)元素尚未被復制之前,就覆蓋其值,導致錯誤結果.在這里我一再使用“可能”這個字眼,是因為,如果copy算法根據其所 接收的迭代器的特性決定調用 memmove() 來執行任務,就不會造成上述錯誤,因 為 memmove() 會先將整個輸人區間的內容復制下來,沒有被覆蓋的危險
    int ia[] = {0,1,2,3,4,5,6,7,8};//輸出區間的終點和輸入的區間重疊  沒有問題std::copy(ia+2,ia+7,ia);std::for_each(ia,ia+9,display<int>());std::cout << "\n";
    // 以下,輸出區間的起點與輸入區間重疊,可能會有問題int ia[] = {0,1,2,3,4,5,6,7,8};std::copy(ia+2,ia+7,ia+4);std::for_each(ia,ia+9,display<int>());std::cout << "\n"; //0 1 2 3 2 3 4 5 6
    int ia[] = {0,1,2,3,4,5,6,7,8};//deque 擁有 RandomAcCGSSltGrCltorstd::deque<int>id(ia,ia+9);std::deque<int>::iterator first = id.begin();std::deque<int>::iterator last = id.end();++++first;  //advance(first,2);std::cout << *first << std::endl; //2----last;   //advance(last,-2);std::cout << *last << std::endl;  //7std::deque<int>::iterator result = std::begin(id);std::cout << * result << std::endl;// 以下,輸出區間的終點與輸入區間重疊,沒問題std::copy(first,last,result);//(2 3 4 5 6) 5 6 7 8std::for_each(id.begin(),id.end(),display<int>{});std::cout << "\n";return 0;
    int ia[] = {0,1,2,3,4,5,6,7,8};//deque 擁有 RandomAcCGSSltGrCltorstd::deque<int>id(ia,ia+9);std::deque<int>::iterator first = id.begin();std::deque<int>::iterator last = id.end();++++first;  //advance(first,2);std::cout << *first << std::endl; //2----last;   //advance(last,-2);std::cout << *last << std::endl;  //7std::deque<int>::iterator result = std::begin(id);std::advance(result,4);std::cout << * result << std::endl;//以下,輸出區間的起點與輸入區間重疊,可能會有問題//本例結果錯誤,因為調用的 copy算法不再使用memmove ()執行實際復制操作std::copy(first,last,result);//0 1 2 3 (2 3 4 5 6std::for_each(id.begin(),id.end(),display<int>{});std::cout << "\n";return 0;
  • 請注意,如果你以vector取代上述的deque進行測試,復制結果將是正確的,因 為 vector迭代器其實是個原生指針(native pointer), 見4.2.3節,導致調用的copy算法以memmove ()執行實際復制操作
  • copy更改的是[result,result + (last-first)) 中的迭代器所指對象,而非更改迭代器本身。它會為輸出區間內的元素賦予新值,而不是產生新的元素。它不能改變輸出區間的迭代器個數。換句話說 , copy不能直接用來將元素插入空容器中。例子如下所示:如果不給myvector申請空間就會出錯,只有申請空間之后初始化為0,然后執行覆蓋原有數值的操作
  • 如果你想要將元素插入(而非賦值)序列之內,要么明白使用序列容器的insert 成員函數,要么使用 copy 算法并搭配 insert_iterator (8.3.1 節 )
  • 現在我們來看看 copy算法龐大的實現細節。下面是冰山一角,也是唯一的對外接口:
int main(int argc,char* argv[]) {int myints[]={10,20,30,40,50,60,70};std::vector<int>myvector(7);std::copy(myints,myints+7,myvector.begin());std::cout << "myvector contains:";for (std::vector<int>::iterator it = myvector.begin();it != myvector.end();++it) {std::cout << ' '<< *it;}std::cout << "\n";return 0;
}

  • ?下面兩個是多載函數,針對原生指針(可視為一種特殊的迭代器)const char*和 const wchar_t*, 進行內存直接拷貝操作:

  • ?這里必須兵分兩路來探討。首先,_ copy_dispatch ()的完全泛化版根據迭代器種類的不同,調用了不同的 一copy()> 為的是不同種類的迭代器所使用的循 環條件不同,有快慢之別.

  • 這 是 __copy_dispatch ()完全泛化版的故事。現在回到前述兵分兩路之處, 看看它的兩個偏特化版本。這兩個偏特化版是在“參數為原生指針形式”的前提下,希望進一步探測“指針所指之物是否具有trivial assignment operator (平凡 賦值操作符)” ? 這一點對效率的影響不小,因為這里的復制操作是由assignment 操作符負責,如果指針所指對象擁有non-trivial assignment operator,復制操作就 一定得通過它來進行。但如果指針所指對象擁有的是trivial assignment operator, 復制操作可以不通過它,直接以最快速的內存對拷方式(memmove ())完成。C++語言本身無法讓你偵測某個對象的型別是否具有trivial assignment operator,但是SGI STL采用所謂的 ?type_traits<> 編程技巧來彌補(見3.7節)。注意,通 過 “增 加一層間接性”的手法,我們便得以區分兩個不同的 ?copy_t():

  • 第三個問題的解答是:我們以為vector的迭代器是random access iterator,沒想到它事實上是個T*?;vector迭代器其實是原生指針。這就怪不得copy。?一旦面對vector 迭代器,就往T*的方向走去了;

?6.4.4 copy_backw ard

  • 將[firstaast)區間內的每一個元素,以逆行的方向復制到 以 result-1為起點,方向亦為逆行的區間上。換句話說,copy_backward算法會
    執行賦值操作 * (result-1) =?* (last-1) , * (result-2 ) = * (last-2 ) , 依此類推。
  • 返回一個迭代器:result- (last-first) □ copy_backward所接受的迭代器必
    須 是 Bidirectionallterators, 才 能 夠 “倒行逆施”。你可以使用copy_backward算
    法,將任何容器的任何一段區間的內容,復制到任何容器的任何一段區間上°如果輸
    入區間和輸出區間完全沒有重疊,當然毫無問題,否則便需特別注意

?

    int ia[] = {0,1,2,3,4,5,6,7,8};//輸出區間的終點和輸入區間重疊 沒問題std::copy_backward(ia+2,ia+7,ia+9);std::for_each(ia,ia+9,display<int>{});//0 1 2 3 2 3 4 5 6std::cout<<std::endl;return 0;
    int ia[] = {0,1,2,3,4,5,6,7,8};//輸出區間的起點和輸入區間重疊 可能會有問題std::copy_backward(ia+2,ia+7,ia+5);std::for_each(ia,ia+9,display<int>{});//2 3 4 5 6 5 6 7 8//本例結果正確,因為調用的copy算法使用memmove ()執行實際復制操作std::cout<<std::endl;return 0;

?

template<class T>
struct display{void operator()(const T&x){std::cout << x << ' ';}
};
int main(int argc,char* argv[]) {int ia[] = {0,1,2,3,4,5,6,7,8};std::deque<int>id(ia,ia+9);std::deque<int>::iterator first = id.begin();std::deque<int>::iterator last = id.end();++++first; //advance(first,2);std::cout << *first << std::endl;----last;  //advance(last,-2);std::cout << *last << std::endl;std::deque<int>::iterator result = id.end();//輸出區間的終點和輸入區間重疊 沒有問題std::copy_backward(first,last,result);std::for_each(id.begin(),id.end(),display<int>{});//0 1 2 3 2 3 4 5 6std::cout<<std::endl;return 0;
}
int main(int argc,char* argv[]) {int ia[] = {0,1,2,3,4,5,6,7,8};std::deque<int>id(ia,ia+9);std::deque<int>::iterator first = id.begin();std::deque<int>::iterator last = id.end();++++first; //advance(first,2);std::cout << *first << std::endl;----last;  //advance(last,-2);std::cout << *last << std::endl;std::deque<int>::iterator result = id.begin();std::advance(result,5);std::cout << *result << std::endl;//輸出區間的起點和輸入區間重疊 可能會有問題std::copy_backward(first,last,result);// 本例結果錯誤,因為調用的copy算法不再使用memmove()執行實際復制操作  但是我實際編碼結果是正確的std::for_each(id.begin(),id.end(),display<int>{});//2 3 4 5 6 5 6 7 8std::cout<<std::endl;return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/446432.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446432.shtml
英文地址,請注明出處:http://en.pswp.cn/news/446432.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

華為彈性云服務器ECS使用學習0

學習大綱 ECS概述 組成&#xff1a;CPU,內存&#xff0c;鏡像&#xff0c;操作系統&#xff0c;云硬盤 ECS產品優勢 彈性伸縮AS&#xff08;彈性可擴展&#xff09; ECS產品架構 Region:地理位置和網絡時延的劃分&#xff0c;同一個Region中共享計算和存儲資源&#xff…

STL源碼剖析 set相關算法

STL 一共提供了四種與set (集合)相關的算法&#xff0c;分別是并集(union)、交集(intersection) > 差集 (difference)、對稱差集 (symmetricdifference所謂set,可細分為數學上的定義和STL的定義兩種&#xff0c;數學上的set允許元素重復而未經排序&#xff0c;例 如 &#x…

C++ 使用遞增的方式初始化 一個 vector

int countOdds(int low, int high) {int count 0;std::vector<int>temp{high-low1,0};int n low;std::generate(temp.begin(),temp.end(),[&]{return n;});for (auto x:temp) {std::cout << x;}} 使用Itoa std::iota int countOdds(int low, int high) {in…

Python學習4 列表基礎知識和常用函數

列表 1.格式 2.增刪改查 列表下標&#xff1a; 0–n-1 -n-(-1) #對列表進行切片 #0-(n-1) #-n-(-1) list[dq,python,mm] print(list[0:2])#[0,2) print(list[-3:-2])#[-3,-2) #輸出 #[dq, python] #[dq]題目&#xff1a; 【1&#xff1a;4&#xff1a;2】:[1,4),步長為2 下…

Python學習5 元組基礎知識和常用函數

元組概念 元組&#xff1a;a&#xff08;1&#xff0c;23&#xff09; 列表&#xff1a;a [1,23] 創建和訪問元組 Python 的元組與列表類似&#xff0c;不同之處在于tuple被創建后就不能對其進行修改&#xff0c;類似字符串。 元組與列表類似&#xff0c;也用整數來對它進行…

STL源碼剖析 仿函數

仿函數 也叫函數對象1&#xff0c;具有函數性質的對象&#xff1b;2&#xff0c;這種東西在調用者可以像函數一樣地被調用(調用)&#xff0c;在被調用者則以對象所定義的function call operator扮 演函數的實質角色。要將某種 “操作”當做算法的參數&#xff0c;唯一辦法就是先…

Python學習6 字典基礎知識和常用函數

字典概念 字典是 Python 提供的一種常用的數據結構&#xff0c;它用于存放具有映射關系的數據。為了保存具有映射關系的數據&#xff0c;Python 提供了字典&#xff0c;字典相當于保存了兩組數據&#xff0c;其中一組數據是關鍵數據&#xff0c;被稱為 key&#xff1b;另一組數…

EndNote概述

概述 EndNote 是SCI&#xff08;Thomson Scientific 公司&#xff09;的官方軟件&#xff0c;支持國際期刊的參考文獻格式有3776 種&#xff0c;寫作模板幾百種&#xff0c;涵蓋各個領域的雜志。簡單來說EndNote的功能就是替你管理文獻&#xff0c;一鍵插入固定格式的參考文獻…

Java web后端2 Servlet Maven HttpServlet ServletConfig ServletContext HTTP協議

創建項目 新建項目 Java Enterprise JDK1.8 Web Application Tomcat JAVA 默認 過程需要聯網 Maven的配置 IDEA內置Maven 修改本地倉庫位置&#xff0c;因為以后會越來越大 替換配置文件&#xff1a; 阿里云鏡像下載 Servlet基礎 1.動態Web資源開發 2.Servlet是使用J…

STL源碼剖析 配接器

配接器(adapters)在 STL組件的靈活組合運用功能上&#xff0c;扮演著軸承、轉換器的角色。Adapter這個概念&#xff0c;事實上是一種設計模式(design pattern)。 Design Patterns)) 一書提到23個最普及的設計模式&#xff0c;其中對odopter樣式的定義如下&#xff1a;將 一個cl…

中科大 計算機網絡3 網絡邊緣Edge

網絡結構 邊緣系統 網絡核心 接入網 方塊&#xff1a;邊緣系統(主機) 圓的&#xff1a;網絡核心&#xff0c;數據交換作用 連接邊緣系統和網絡核心的叫做接入網&#xff08;access&#xff09;&#xff0c;把邊緣的主機接入到網絡核心&#xff08;所以是分布式的&#xff09; …

STL源碼剖析 入門開始 STL概論與版本簡介

源代碼之中時而會出現一些全局函數調用操作&#xff0c;尤其是定義于<stl_construct.h> 之中用于對象構造與析構的基本函數&#xff0c;以及定義于<stl_uninitialized.h>之 中 用 于 內 存 管 理 的 基 本 函 數 &#xff0c; 以及定義于<stl_algobase.h>之中…

中科大 計算機網絡4 網絡核心Core 分組交換 電路交換

網絡核心 電路交換&#xff08;線路交換&#xff09;&#xff1a;打電話之前&#xff0c;先建立一條鏈路&#xff08;物理&#xff09; 分組交換&#xff1a;存儲轉發的方式 電路交換&#xff08;線路交換&#xff09; 通過信令&#xff08;控制信息&#xff0c;如&#xf…

STL 源碼剖析 空間配置器

以STL的運用角度而言&#xff0c;空間配置器是最不需要介紹的東西&#xff0c;它總是隱藏在一切組件&#xff08;更具體地說是指容器&#xff0c;container&#xff09; 的背后但是STL的操作對象都存放在容器的內部&#xff0c;容器離不開內存空間的分配為什么不說allocator是內…

中科大 計算機網絡7 分組延遲 分組丟失 吞吐量

分組丟失和延遲的原因 隊列太長沒有意義&#xff0c;用戶需求 排隊&#xff1a;輸出能力<到來的分組&#xff0c;需要等待 四種分組延遲 節點處理延遲&#xff1a;確定的 排隊延遲&#xff1a;隨機&#xff0c;取決于網絡情況 一個比特的傳輸時間&#xff1a; R1Mbps …

STL源碼剖析 迭代器iterator的概念 和 traits編程技法

iterator模式定義如下&#xff1a;提供一種方法&#xff0c;使之能夠依序巡訪某個 聚合物(容器)所含的各個元素&#xff0c;而又無需暴露該聚合物的內部表述方式.STL的中心思想在于&#xff1a;將數據容器(containers)和算法(algorithms)分開&#xff0c;彼此獨立設計&#xff…

中科大 計算機網絡11 應用層原理

應用層大綱 傳輸層向應用層提供的服務&#xff0c;形式是Socket API&#xff08;原語&#xff09; 一些網絡應用的例子 互聯網層次中&#xff0c;應用層協議最多 流媒體應用&#xff1a;直播 網絡核心最高的層次就是網絡層 應用進程通信方式 C/S&#xff1a; 客戶端&…

STL源碼剖析 序列式容器 vector 和 ilist

Vector list 單向鏈表 ilistlist的刪除操作&#xff0c;也只有指向被刪除元素的迭代器會失效&#xff0c;其他迭代器不會受到影響

中科大 計算機網絡5 接入網和物理媒體

接入網 接入網&#xff1a;把邊緣&#xff08;主機&#xff09;接入核心&#xff08;路由器&#xff0c;交換機&#xff09; 骨干網【連接主機和主機】和接入網中都有物理媒體 接入方式&#xff1a;有線和無線 帶寬共享/獨享 接入網&#xff1a;住宅接入modem modem調制解調…

STL源碼剖析 序列式容器 deque雙端隊列

相較于vector的內存拷貝&#xff0c;deque在內存不足時只需要進行內存的拼接操作即可&#xff0c;不需要重新配置、復制、釋放等操作&#xff0c;代價就是迭代器的架構不是一個普通的指針&#xff0c;比較復雜d e q u e 的迭代器 deque是分段連續空間。維持其“整體連續”假象…