重拾C 泛型演算法

2021-07-22 04:24:59 字數 4095 閱讀 7871

vector有一些操縱大小的操作,capacity()列印現在的大小,reserve(n)保持儲存n個元素,shrink_to_fit()將capacity恢復到現在

容器的大小。reserve並不會減少空間或代替resize的能力。看來這種相當的簡單。

跳過下面有關string的部分。

容器介面卡,是基於一些順序容器構造的資料結構,這些資料結構要根據基本的底層容器進行初始化。(利用已初始化的命名物件進行初始化)

但對介面卡本身進行改變後,並不能對相應的底層容器進行相應的訪問操作,特別地,底層容器的size等並沒有改變。

這僅僅是用來初始化,(而且不能對有元素的底層容器進行初始化)而非實際儲存。

棧stack提供4種操作,push pop emplace top(對應於類vector的 front end)

queue僅僅是具備先進先出的特性,priority queue具備按優先順序進行排序的特點。(進出特性明確)

queue可以用vector作為底層容器實現的原因可能在於erase方法。關於優先佇列介面卡的部分且不述,編譯器並未支援。

下面展開有關泛型演算法的討論。

泛型演算法的設定是對迭代器範圍內的元素進行處理。

find:查詢指定元素,並返回指定元素的迭代器,如沒有,返回第二個迭代器(「尾後」迭代器)。

由於其嚴謹的泛型形式導致其不能在string中對子string進行查詢。

將find函式應用於指標範圍也是可以的,一般指標由begin end 函式(不需要載入庫)得到。

泛型演算法一般和序有關的操作應當依賴於容器類中的"==",但相應的操作可以通過指定謂詞來進行(不需要過載操作符)。

其進行的操作可以視為迭代進行,並不改變容器大小,這可以從algorithm remove中看到。

想利用remove刪除元素,可以利用remove返回移動後原迭代範圍的尾後迭代器,結合erase範圍刪除得解。

numeric accumudate演算法將範圍元素進行「累加」,並將第三個引數作為初值傳入。(這裡存在允許型別轉換的假定)

algorithm equal由於相同容器例項化型別封裝了"==",equal主要用來在不同容器間進行比較,接受乙個迭代範圍及另乙個範圍

的起始迭代器。對於封裝比較operator的說明,以自定義的過載運算為準。

algorithm fill向乙個容器範圍寫入給定的元素(第三個引數)

fill_n接受三個引數,寫入的起始迭代器,寫入元素的數量,寫入的值。(可以將某容器元素都設定為某值)

容器庫泛型演算法,並不能對容器大小進行改變,與之相對的,iterator庫中提供了可以插入容器元素的迭代器,

但在容器操作上並沒有什麼實質上的不同。僅僅是提供了不同的介面。

以iterator::back_inserter為例,利用其對某一容器進行初始化,返回乙個可以執行尾部插入的迭代器,但其內部仍然呼叫

push_back方法。(只有能執行相關操作的容器才能這樣做)

如果是單純地使用iterator的上述相應所謂迭代器介面卡,其結果與基本操作無異,但是將其作為泛型演算法迭代器範圍的引數,

能起到加成的作用,比如將上述back_inserter應用於fill_n 即可實現不已迭代為形式的擴張插入。

標準庫begin end函式被定義在標頭檔案iterator中,被用來返回迭代器。

對拷貝演算法,其常常與back_inserter相配合使用。這裡對back_inserter的看法是相對模糊的,但能夠理解。

對於容器中元素進行改變的演算法,一般有兩個版本,一種是改變原容器,另一種是得到乙個拷貝(原容器不變)

以replace為例,replace接受4個引數,前兩個是迭代器範圍,後兩個是將某值替換為其它值。這是乙個該變原容器的演算法,

不改變的版本為replace_copy,其接受第三個引數(共5個引數)為將改變後的版本插入的位置。

對容器元素的重排(元素過載序運算)刪除多呼叫標準庫algorithm::sort 及 unique,後者返回第乙個不滿足唯一性的迭代器,

之後使用erase即可。sort具有可選的第三個引數作為排序的謂詞(bool型別函式指定序)。

在自定義謂詞進行排序時,涉及乙個問題,即是新序對舊序的完全替換還是,在舊序上發展而來,

在這裡,有stable_sort方法實現在首先滿足新序的情況下,利用舊序對新序下相等的元素進一步排(即序的優先順序問題)

標準庫algorithm::find_if 對乙個迭代器範圍尋找第乙個符合第三個引數(謂詞)的迭代器。(否則返回尾後)

lambda表示式,的注意事項:lambda表示式必須包含捕獲引數列表(可以是空列表),其它部分在理論上是可以省略的。

當lambda函式體僅由乙個return語句組成時。(此時與python中的lambda表示式是等價的),省略的返回值

型別可以由編譯器推斷獲得。(可省略)

但當lambda函式體中除了return還有其它語句時,如果省略返回值型別,會將返回值型別置為void,應當保持返回

值型別的寫作。(雖然實現由編譯器實現可能導致對的情況)

auto f = [capture list](para list)-> return_type; (注意  ;  的安排)

由於演算法所指定接收的謂詞一般僅對容器中的元素提供介面,當想要動態地將與處理結果有關的引數傳入謂詞時問題有一些麻煩,

這在指令碼語言中是容易的(在python中,其轉化為對函式提供預設引數或動態地指定某引數值的問題,利用functools.partial

可以很好地解決),但在c++中就需要利用閉包的概念。

程式設計中閉包的一大特性是可以將閉包置於另乙個環境(函式環境)中,並使用該環境中的變數(如python函式巢狀定義),

實際在數學中就相當於對乙個空間指定子空間,子空間具有空間的全部性質,可見python所定義的函式空間「太好了」。

這與數學中的閉包特性是基本吻合的。對於距離空間的乙個子集,可以得到這個子集的閉包,在閉包中進行cauchy收斂,

所收斂的點都在此閉包中,閉包是自治的。由於要求閉包的這種自治性,對於大多數支援變數即是物件的指令碼語言,閉包會有較好的支援。

lambda表示式:

基本具備形式 [capture list](parameter list) -> return type

一般返回引數形式可以由function body推得,故最簡形式為:

(parameter list)

注意:這裡有時捕獲列表沒有捕獲變數,但也需要給出空列表。

宣告lambda表示式這一可呼叫物件,一般儲存此部分時要宣告相應的型別,

最為簡單的方法是將其賦給auto進行自動型別推斷,

顯式宣告也是可以的,採用functional庫中的function模板對返回值及引數

組成的元素進行例項化即可。

如:functionb = (const int&i);

就是儲存可呼叫物件的一種方法。

對lambda表示式中捕獲引數列表中的引數一般可以有兩種操作,即改變與不改變

兩種。進行改變操作時,應將其宣告為引用。否則對非引用形式的捕獲引數變數

在lambda函式體中進行改變會被視為非法的。(直接編譯出錯,提示read only 

valuable)

lambda表示式實現了閉包的概念,一般地如上初始化乙個lambda表示式是採用

只閉不包的形式,即限定表示式的變數環境。

但也可以在捕獲列表中使用= 或 & 將所有外包的環境變數包含在內部體中。

對於上面的值捕獲及引用捕獲方式,也可以採用混合的方法,即在捕獲列表中

既宣告全體的值捕獲,又宣告個體的引用捕獲。

由於c++的編譯特性,導致在lambda表示式捕獲列表宣告時,要求捕獲的表示式在之前

宣告時必須是已定義的,並且在宣告後對此變數進行改變不會改變在編譯期已經

決定的捕獲變數值,這與python等動態型別語言是不同的。

當然這是值拷貝的情況:

ex:

size_t v1 = 42;

auto f = [v1]()mutable;

v1 = 0;

auto i = f();

cout << i );        cout << endl;

}

一些如插入迭代器之類的back_inserter(back_insert_iterator) inserter等顯式宣告其型別是比較麻煩的,

可用auto宣告型別。

重拾C 教程 環境

在這一章中,我們將討論建立 c 程式設計所需的工具。我們已經提到 c 是 net 框架的一部分,且用於編寫 net 應用程式。因此,在討論執行 c 程式的可用工具之前,讓我們先了解一下 c 與 net 框架之間的關係。net 框架是乙個創新的平台,能幫您編寫出下面型別的應用程式 net 框架應用程式...

重拾C 教程 封裝

封裝被定義為 把乙個或多個專案封閉在乙個物理的或者邏輯的包中 在物件導向程式設計方 中,封裝是為了防止對實現細節的訪問。抽象和封裝是物件導向程式設計的相關特性。抽象允許相關資訊視覺化,封裝則使開發者實現所需級別的抽象。c 封裝根據具體的需要,設定使用者的訪問許可權,並通過訪問修飾符來實現。乙個訪問修...

重拾C 教程 列舉

列舉是一組命名整型常量。列舉型別是使用enum關鍵字宣告的。c 列舉是值型別。換句話說,列舉包含自己的值,且不能繼承或傳遞繼承。宣告列舉的一般語法 enum 其中,列舉列表中的每個符號代表乙個整數值,乙個比它前面的符號大的整數值。預設情況下,第乙個列舉符號的值是 0.例如 enum days 下面的...