C++ 提高編程:模板與 STL 深度剖析

摘要:本文深入探討 C++ 提高編程中的模板編程與標準模板庫(STL)相關內容。詳細闡述模板編程中函數模板和類模板的概念、語法、特性及應用案例;對 STL 的誕生背景、基本概念、六大組件進行剖析,并對常用容器、函數對象、常用算法展開全面講解,旨在為 C++ 開發者提供系統且深入的技術參考,助力其提升 C++ 編程能力與代碼質量。

一、引言

????????C++ 作為一種強大且應用廣泛的編程語言,其提高編程部分涵蓋的模板編程和 STL,為開發者提供了高度的代碼復用性和強大的數據處理能力。模板編程實現了泛型編程,使代碼能夠獨立于具體數據類型;STL 則是一套精心設計的模板庫,包含容器、算法和迭代器等組件,極大地簡化了復雜數據結構和算法的實現。深入理解和掌握這些內容,對提升 C++ 編程水平至關重要。

二、模板編程

(一)模板概念

????????模板是 C++ 泛型編程的基礎,它允許將類型作為參數傳遞給函數或類,從而實現代碼的復用。通過模板,算法可以獨立于具體的數據類型,提高了代碼的通用性和可維護性。其核心基于類型參數化,使得同一套代碼能夠處理不同類型的數據,減少了重復代碼的編寫。

(二)函數模板

  1. 語法
    函數模板以template <typename T>template <class T>的形式聲明模板參數,其中typenameclass含義相同,用于指定類型參數。在函數定義中,使用該模板參數來表示函數的參數類型或返回值類型。例如:
template <typename T>
T add(T a, T b) {return a + b;
}
  1. 注意事項
    類型推導存在一定規則,編譯器優先匹配精確類型,當無法自動推導模板參數類型時,需要開發者顯式指定。同時,在模板參數匹配時,普通函數的優先級高于函數模板。
  2. 案例
    實現一個通用的數組元素交換函數:
template <typename T>
void swapArray(T arr[], int i, int j) {T temp = arr[i];arr[i] = arr[j];arr[j] = temp;
}

????????此函數可用于交換不同類型數組中的元素,展示了函數模板的便捷性。再如編寫通用的最大值獲取函數:

template <typename T>
T getMax(T a, T b) {return (a > b)? a : b;
}

????????體現了函數模板對不同數據類型的適用性。
4.?與普通函數區別
????????函數模板具有類型通用性,能夠處理多種數據類型;而普通函數針對特定類型編寫。在編譯時,函數模板會根據實際傳入的參數類型進行實例化,生成對應類型的函數代碼,普通函數則直接進行編譯。
5.?調用規則
????????自動類型推導:編譯器根據傳入函數的參數自動確定模板參數的類型,如int result = add(3, 5);。顯式指定類型:開發者明確指定模板參數類型,例如add<int>(3, 5)
6.?局限性
????????對于一些特定類型的操作,如位運算等,函數模板可能需要特殊處理。此外,大量實例化可能導致代碼體積膨脹,占用更多的存儲空間。

(三)類模板

  1. 語法
    類模板的聲明形式為template <typename T> class ClassName {...}?,在類內部可以使用模板參數T定義成員變量和成員函數。成員函數既可以在類內直接定義,也可以在類外實現。類外實現成員函數時,語法如下:
template <typename T>
return_type ClassName<T>::function_name(parameters) {...}
  1. 與函數模板區別
    類模板作用于整個類及其對象實例,而函數模板僅作用于函數。類模板可包含多種成員,如數據成員、成員函數等,結構更為復雜,涉及到類的封裝、繼承和多態等特性與模板的結合。
  2. 成員函數創建時機
    類模板的成員函數在調用時才會進行實例化,生成對應類型的函數代碼。提前聲明成員函數并不立即實例化,這種延遲實例化機制可以節省編譯時間,只有在實際使用時才進行實例化操作。
  3. 對象做函數參數
    按值傳遞:將對象復制一份傳遞給函數,這種方式開銷較大,適用于小對象或無需保留原對象狀態的情況。例如:
template <typename T>
void printObjectByValue(T obj) {std::cout << obj << std::endl;
}

????????引用傳遞:傳遞對象的引用給函數,高效且能修改對象內容,同時避免了拷貝構造的開銷。如:

template <typename T>
void modifyObjectByReference(T& obj) {// 修改obj操作
}

????????指針傳遞:通過指針傳遞對象,具有較高的靈活性,可實現多態等特性,但需要注意指針的有效性。示例如下:

template <typename T>
void operateOnObjectByPointer(T* ptr) {// 通過指針操作對象
}
  1. 與繼承
    類模板繼承普通類:子類模板可以繼承普通類的屬性和方法,并在此基礎上添加模板特性。例如,普通類實現了一些通用的功能,類模板繼承后可以針對不同類型進行定制化擴展。
    類模板之間繼承:子類模板可以繼承父類模板的參數及功能,并且可以進一步擴展新的模板參數或成員。在繼承過程中,需要注意模板參數的傳遞和處理,確保繼承關系的正確性和代碼的可讀性。
  2. 成員函數類外實現
    類模板成員函數類外實現時,需遵循特定語法,明確指定模板參數。同時要注意作用域的限定,確保編譯器能夠正確識別和編譯。例如:
template <typename T>
class MyClass {
public:void function();
};template <typename T>
void MyClass<T>::function() {// 函數實現代碼
}

  1. 分文件編寫
    頭文件:主要用于聲明類模板及其成員函數,為其他文件提供接口。在頭文件中,應包含必要的模板聲明和類的前置聲明,確保其他源文件能夠正確引用。
    源文件:實現類模板的成員函數。在編譯時,需要正確處理模板實例化問題,常見的解決方法包括顯式實例化或在源文件中包含頭文件等方式,以避免編譯鏈接錯誤。
  2. 與友元
    普通函數友元:授予普通函數訪問類模板私有成員的權限,通過在類模板中聲明友元函數來實現。例如:
template <typename T>
class MyClass {friend void friendFunction(MyClass<T>& obj);
private:T data;
};template <typename T>
void friendFunction(MyClass<T>& obj) {// 訪問obj的私有成員data
}

????????函數模板友元:函數模板可以作為類模板的友元,實現特定功能的交互。在聲明和實現時,需要注意模板參數的匹配和作用域的處理。
????????類模板友元:一個類模板可以作為另一個類模板的友元,從而實現兩個類模板之間的數據共享或功能協作。在這種情況下,需要仔細設計友元關系,確保代碼的安全性和可維護性。
9.?案例
????????實現通用的鏈表類模板:

template <typename T>
class LinkedList {
private:struct Node {T data;Node* next;Node(const T& value) : data(value), next(nullptr) {}};Node* head;
public:LinkedList() : head(nullptr) {}// 鏈表操作函數,如插入、刪除、遍歷等
};

????????該類模板可用于管理不同類型數據的鏈表節點,實現鏈表的基本操作。再如構建通用的矩陣類模板:

template <typename T>
class Matrix {
private:int rows;int cols;T** elements;
public:Matrix(int r, int c) : rows(r), cols(c) {elements = new T*[rows];for (int i = 0; i < rows; ++i) {elements[i] = new T[cols];}}// 矩陣運算函數,如加法、乘法等
};

????????實現矩陣的存儲和運算功能,展示類模板在復雜數據結構中的應用。

三、STL 初識

(一)STL 誕生

????????STL 起源于惠普實驗室,由 Alexander Stepanov 等人開發。其設計目標是提供一套通用、高效、可復用的模板庫,旨在簡化 C++ 編程中數據結構和算法的實現,減少開發者的重復勞動,提高軟件開發的效率和質量。

(二)基本概念

  1. 容器:用于存儲數據,是 STL 的重要組成部分。類似于不同的數據結構,如數組、鏈表、集合等,提供了不同的存儲和訪問方式,滿足各種應用場景對數據存儲的需求。
  2. 算法:對容器中的數據進行操作,涵蓋排序、查找、遍歷等多種操作。STL 算法具有高度的通用性,能夠處理不同類型的容器數據,通過迭代器與容器進行交互。
  3. 迭代器:類似于指針,用于訪問容器中的元素,為容器提供了統一的訪問接口。迭代器的存在使得算法可以不依賴于具體容器的實現細節,實現了容器和算法的分離與通用化。

(三)六大組件

  1. 容器
    順序容器:如vectorlistdeque等,它們按照元素的插入順序存儲元素。vector是動態數組,具有連續的內存存儲,支持隨機訪問,適合頻繁訪問元素的場景;list是雙向鏈表,不支持隨機訪問,但在頻繁插入和刪除元素時效率較高;deque是雙端隊列,允許在兩端進行高效的插入和刪除操作,兼具vectorlist的部分特性。
    關聯容器:包括setmap等,這些容器根據特定的鍵值關系存儲元素。set中的元素唯一且自動排序,常用于快速查找和去重;map以鍵值對的形式存儲數據,鍵唯一且自動排序,可用于高效的鍵值查找。
  2. 算法
    分為多種類型,如遍歷算法用于逐個訪問容器中的元素;查找算法用于在容器中尋找特定元素或滿足條件的元素;排序算法用于對容器中的元素進行排序等。不同的算法針對不同的應用需求,提供了豐富的數據處理功能。
  3. 迭代器
    輸入迭代器:只讀,支持單遍掃描容器,用于從容器中讀取數據。
    輸出迭代器:只寫,用于向容器中寫入數據。
    前向迭代器:支持讀寫操作,只能單遍掃描容器,按順序向前訪問元素。
    雙向迭代器:支持讀寫操作,可在容器中前后移動,適用于需要雙向遍歷的場景。
    隨機訪問迭代器:支持讀寫操作,并且可以隨機訪問容器中的元素,具有類似指針算術運算的能力,如vector的迭代器。
  4. 仿函數
    即函數對象,通過類重載()運算符實現。仿函數可以作為算法的參數,用于定制算法的操作邏輯。例如,在排序算法中,可以使用自定義的仿函數作為比較函數,實現特定的排序規則。
  5. 適配器
    容器適配器:如stackqueue等,它們改變了其他容器的接口,使其符合特定的數據結構特性。stack遵循后進先出原則,queue遵循先進先出原則,它們底層通常基于其他容器(如dequevector等)實現。
    迭代器適配器:如reverse_iterator,它改變了迭代器的遍歷方向,使算法可以反向遍歷容器。
  6. 分配器
    負責容器的內存分配與釋放,默認情況下使用系統的內存分配機制。開發者也可以自定義分配器,以滿足特定的內存管理需求,如提高內存分配效率、實現內存池等功能。

(四)容器、算法、迭代器

????????迭代器在容器和算法之間起到橋梁作用。算法通過迭代器來訪問和操作容器中的元素,使得算法能夠獨立于具體容器的實現。容器提供了數據的存儲結構,而算法基于迭代器對容器中的數據進行處理,這種設計模式實現了容器和算法的分離與高度復用,提高了代碼的可維護性和擴展性。

(五)容器算法迭代器初識

  1. vector 存放內置數據類型
    語法:定義vector<int> v;創建一個存儲int類型數據的vector容器。插入元素使用v.push_back(5);,訪問元素可以通過v[0]v.at(0)at函數帶有邊界檢查)。
    動態內存管理:vector會根據元素的插入自動擴展內存,采用連續內存存儲方式,這使得元素訪問效率較高,同時也支持隨機訪問。
  2. vector 存放自定義數據類型
    適配:自定義數據類型需要實現合適的構造函數、拷貝構造函數、賦值運算符等,以滿足vector對元素的存儲和操作要求。例如,如果自定義類沒有正確實現拷貝構造函數,在vector進行元素拷貝(如插入、刪除等操作可能涉及拷貝)時可能會出現錯誤。
    操作:可以對存放自定義數據類型的vector進行排序、查找等操作,但通常需要定制比較函數等,以確保操作符合自定義類型的邏輯。
  3. vector 容器嵌套容器
    應用場景:常用于表示二維數據結構,如二維數組表示矩陣、表格等。例如,vector<vector<int>> matrix;可以表示一個整數矩陣。
    內存布局與訪問:外層vector管理內層vector的指針,內存并非完全連續。訪問元素時需要通過兩層索引,如matrix[i][j]來訪問第i行第j列的元素。

四、STL - 常用容器

(一)string 容器

  1. 基本概念
    string容器用于動態存儲字符串,它自動管理內存,相比 C 風格字符串更加安全和易用。其內部采用類似vector的結構來存儲字符數據,提供了豐富的操作接口來處理字符串。
  2. 構造函數
    默認構造:string s;創建一個空字符串。
    拷貝構造:string s1(s);將已有字符串s復制給s1
    初始化列表構造:string s2("hello");使用字符串字面量初始化s2
  3. 賦值操作
    重載=運算符:s = "world";直接將字符串字面量賦值給s
    assign 函數:提供多種賦值方式,如s.assign("new string", 3);表示取"new string"的前 3 個字符賦值給s
  4. 字符串拼接
    重載+運算符:s = s + "!";"!"拼接到字符串s后面。
    append 函數:s.append(" append");可指定位置和長度進行字符串拼接,如s.append(" append", 3);表示拼接" app"
  5. 查找和替換
    find 函數:size_t pos = s.find("ll");用于查找子串"ll"在字符串s中的位置。
    replace 函數:s.replace(pos, 2, "XX");將從位置pos開始長度為 2 的子串替換為"XX"
  6. 字符串比較
    重載比較運算符:如if (s1 == s2)通過重載的==運算符按字典序比較兩個字符串。
    比較規則:從左到右逐個字符比較 ASCII 碼值,若所有字符都相同則字符串相等,否則根據第一個不同字符的 ASCII 碼大小確定字符串的大小關系。
  7. 字符存取
    重載[]運算符:char c = s[0];直接訪問字符串s的第一個字符。
    at 函數:char c1 = s.at(0);[]類似,但at函數帶有越界檢查,當訪問越界時會拋出異常。
  8. 插入和刪除
    insert 函數:s.insert(1, "x");在字符串s的索引位置 1 處插入字符"x"
    erase 函數:s.erase(1, 2);刪除字符串s從索引位置 1 開始長度為 2 的字符。
  9. 子串
    substr 函數:string sub = s.substr(1, 3);獲取字符串s從索引位置 1 開始長度為 3 的子串。
    應用場景:常用于文本解析、字符串截取等操作,例如從一個完整的文件名中截取文件擴展名。

(二)vector 容器

????????resize 和 reserve 函數:resize函數用于改變vector中元素的個數,可指定初始值,例如v.resize(10, 0)vector的大小調整為 10,新添加的元素初始值為 0;reserve函數用于調整vector的容量,不改變元素個數,它可以提前分配內存,減少內存重新分配的開銷,如v.reserve(20)表示為v預留能容納 20 個元素的內存空間。
5.?插入和刪除
????????push_back 函數:在vector的尾部插入元素,v.push_back(6);將元素 6 添加到vector的末尾。
????????insert 函數:可以在指定位置插入元素,v.insert(v.begin() + 1, 7);表示在vector的第二個位置(索引為 1)插入元素 7。
????????pop_back 函數:刪除vector尾部的元素,v.pop_back();移除vector的最后一個元素。
????????erase 函數:刪除指定位置或范圍的元素,v.erase(v.begin() + 2);刪除vector中索引為 2 的元素;v.erase(v.begin() + 1, v.begin() + 3);則刪除從索引 1 到索引 2(不包括索引 3)的元素。
6.?數據存取
????????重載[]運算符:通過v[0]可以直接訪問vector中索引為 0 的元素。
????????at 函數:v.at(0)[]運算符功能類似,但at函數會進行越界檢查,若索引越界會拋出異常,而[]運算符在越界時行為未定義。
7.?互換容器
????????swap 函數:swap(v, v1);用于交換兩個vector容器的內容。這在某些場景下可以用于內存優化,例如當需要快速交換兩個vector的元素時,使用swap函數比逐個元素交換效率更高。
8.?預留空間
????????reserve 函數:如前面所述,reserve函數可以提前為vector分配內存,避免在插入元素時頻繁進行內存重新分配。例如,當已知需要向vector中插入大量元素時,提前調用reserve函數可以顯著提高程序性能。

(三)deque 容器

  1. 基本概念
    deque(雙端隊列)允許在隊列的兩端進行插入和刪除操作,與vector相比,它在頭部和尾部的操作更加高效。其內存結構是分段連續的,通過映射表來管理各個內存塊,這使得它在需要頻繁在兩端操作元素的場景中表現出色。
  2. 構造函數
    默認構造:deque<int> d;創建一個空的deque容器。
    帶參數構造:deque<int> d1(5, 8);創建一個包含 5 個元素,每個元素值為 8 的deque
  3. 賦值操作
    重載=運算符:d = d1;d1的內容復制給d
    assign 函數:d.assign(4, 9);用 4 個值為 9 的元素替換d原來的內容。
  4. 大小操作
    size 函數:用于獲取deque中元素的個數,int s = d.size();
    empty 函數:判斷deque是否為空,bool isEmpty = d.empty();
  5. 插入和刪除
    push_front 函數:在deque的頭部插入元素,d.push_front(1);將元素 1 添加到deque的開頭。
    push_back 函數:在deque的尾部插入元素,d.push_back(2);將元素 2 添加到deque的末尾。
    pop_front 函數:刪除deque頭部的元素,d.pop_front();移除deque的第一個元素。
    pop_back 函數:刪除deque尾部的元素,d.pop_back();移除deque的最后一個元素。
    insert 函數:可以在指定位置插入元素,d.insert(d.begin() + 1, 3);deque的第二個位置(索引為 1)插入元素 3。
    erase 函數:刪除指定位置或范圍的元素,d.erase(d.begin() + 2);刪除deque中索引為 2 的元素;d.erase(d.begin() + 1, d.begin() + 3);刪除從索引 1 到索引 2(不包括索引 3)的元素。
  6. 數據存取
    重載[]運算符:通過d[0]可以直接訪問deque中索引為 0 的元素。
    at 函數:d.at(0)[]運算符功能類似,但at函數會進行越界檢查,若索引越界會拋出異常,而[]運算符在越界時行為未定義。
  7. 排序
    deque可以使用sort算法進行排序,例如sort(d.begin(), d.end());。如果需要按照特定的規則進行排序,可以自定義比較函數,將其作為sort算法的參數,實現對deque中元素的定制化排序。

(四)案例 - 評委打分

  1. 案例描述
    該案例模擬比賽評分的場景,在比賽中多位評委為選手打分,為了保證評分的公正性,需要去除一個最高分和一個最低分,然后計算剩余分數的平均值,以此作為選手的最終得分。此案例涉及到數據的存儲、處理和結果的輸出等環節,通過使用 STL 容器和算法可以高效地實現。
  2. 實現步驟
    數據錄入:使用合適的容器(如vector)來存儲評委的分數。例如,vector<double> scores;然后通過循環等方式將評委的分數依次錄入到容器中,如scores.push_back(score);(其中score為從輸入獲取的評委分數)。
    數據處理:首先查找容器中的最高分和最低分,可以使用max_elementmin_element算法,如auto maxIt = max_element(scores.begin(), scores.end());auto minIt = min_element(scores.begin(), scores.end());。然后從容器中刪除最高分和最低分,scores.erase(maxIt);scores.erase(minIt);。最后計算剩余分數的平均值,通過累加剩余分數并除以剩余分數的個數來實現,如double sum = accumulate(scores.begin(), scores.end(), 0.0); double average = sum / scores.size();
    結果輸出:將計算得到的選手最終得分輸出顯示,如cout << "選手的最終得分是: " << average << endl;

(五)stack 容器

  1. 基本概念
    ??stack是一種遵循后進先出(LIFO)原則的數據結構。在實際應用中,常用于函數調用棧的模擬、表達式求值(如后綴表達式計算)等場景。它底層通常基于其他容器(如dequevector)實現,通過對這些容器的接口進行封裝,使其符合棧的特性。
  2. 常用接口
    push 函數:用于將元素壓入棧頂,s.push(5);將元素 5 添加到棧s的頂部。
    pop 函數:用于移除棧頂的元素,s.pop();刪除棧s的棧頂元素。
    top 函數:用于獲取棧頂的元素,但不刪除該元素,int topVal = s.top();獲取棧s的棧頂元素值。
    size 函數:用于獲取棧中元素的個數,int stackSize = s.size();
    empty 函數:用于判斷棧是否為空,bool isStackEmpty = s.empty();

(六)queue 容器

  1. 基本概念
    ??queue是一種遵循先進先出(FIFO)原則的數據結構。在實際應用中,常用于消息隊列、任務隊列等場景,例如在多線程編程中,任務可以按照先進先出的順序放入任務隊列,然后由線程依次取出執行。它底層也通常基于其他容器(如dequelist)實現,通過封裝容器接口來滿足隊列的特性。
  2. 常用接口
    push 函數:用于將元素插入隊尾,q.push(3);將元素 3 添加到隊列q的末尾。
    pop 函數:用于移除隊頭的元素,q.pop();刪除隊列q的隊頭元素。
    front 函數:用于獲取隊頭的元素,但不刪除該元素,int frontVal = q.front();獲取隊列q的隊頭元素值。
    back 函數:用于獲取隊尾的元素,但不刪除該元素,int backVal = q.back();獲取隊列q的隊尾元素值。
    size 函數:用于獲取隊列中元素的個數,int queueSize = q.size();
    empty 函數:用于判斷隊列是否為空,bool isQueueEmpty = q.empty();

(七)list 容器

  1. 基本概念
    ??list是一個雙向鏈表,它的每個節點都包含一個指向前驅節點和一個指向后繼節點的指針。由于其內存不是連續的,因此不支持隨機訪問,但是在頻繁進行插入和刪除操作時具有較高的效率。適用于需要頻繁插入和刪除元素,而對隨機訪問需求較少的場景,如實現一個動態的任務列表,任務可以隨時添加或刪除。
  2. 構造函數
    默認構造:list<int> l;創建一個空的list容器。
    帶參數構造:list<int> l1(4, 7);創建一個包含 4 個元素,每個元素值為 7 的list
  3. 賦值操作
    重載=運算符:l = l1;l1的內容復制給l
    assign 函數:l.assign(3, 8);用 3 個值為 8 的元素替換l原來的內容。
  4. 插入和刪除
    push_front 函數:在list的頭部插入元素,l.push_front(1);將元素 1 添加到list的開頭。
    push_back 函數:在list的尾部插入元素,l.push_back(2);將元素 2 添加到list的末尾。
    pop_front 函數:刪除list頭部的元素,l.pop_front();移除list的第一個元素。
    pop_back 函數:刪除list尾部的元素,l.pop_back();移除list的最后一個元素。
    insert 函數:可以在指定位置插入元素,l.insert(l.begin(), 3);list的開頭插入元素 3。
    erase 函數:刪除指定位置或范圍的元素,l.erase(l.begin() + 1);刪除list中索引為 1 的元素;l.erase(l.begin() + 1, l.begin() + 3);刪除從索引 1 到索引 2(不包括索引 3)的元素。
  5. 數據存取
    由于list不支持隨機訪問,因此不能像vector那樣通過下標直接訪問元素。需要通過迭代器來遍歷list,例如:
for (auto it = l.begin(); it != l.end(); ++it) {int val = *it;// 對val進行操作
}
  1. 排序
    list可以使用sort函數進行排序,l.sort();。同樣,如果需要按照特定的規則進行排序,可以自定義比較函數,將其作為sort函數的參數,實現對list中元素的定制化排序。

(八)set/multiset 容器

  1. 基本概念
    set是一個集合容器,其中的元素唯一且自動排序,底層通常使用紅黑樹實現。這種數據結構使得在set中查找元素的效率較高,適用于需要快速查找和去重的場景,例如統計一篇文章中不重復的單詞。
    multisetset類似,也是基于紅黑樹實現,但其允許元素重復,適用于需要統計元素出現次數等場景,比如統計一個班級學生成績中各個分數的出現次數。
  2. 構造和賦值
    默認構造:set<int> s;multiset<int> ms;分別創建一個空的setmultiset容器。
    拷貝構造:set<int> s1(s);multiset<int> ms1(ms);分別將已有的setmultiset容器進行復制。
    賦值運算符重載:s = s1;ms = ms1;分別實現setmultiset容器之間的賦值操作。
  3. 大小和交換
    size 函數:用于獲取setmultiset中元素的個數,int setSize = s.size();int multisetSize = ms.size();
    empty 函數:用于判斷setmultiset是否為空,bool isSetEmpty = s.empty();bool isMultisetEmpty = ms.empty();
    swap 函數:swap(s, s1);swap(ms, ms1);分別用于交換兩個set或兩個multiset容器的內容。
  4. 插入和刪除
    insert 函數:用于向setmultiset中插入元素,s.insert(5);ms.insert(5);分別向setmultiset中插入元素 5。在set中,如果插入的元素已經存在,則插入操作不會生效;而在multiset中,相同元素可以多次插入。
    erase 函數:用于刪除指定的元素或范圍,s.erase(s.find(5));ms.erase(ms.find(5));分別刪除setmultiset中值為 5 的元素(在multiset中會刪除所有值為 5 的元素);s.erase(s.begin(), s.end());ms.erase(ms.begin(), ms.end());分別刪除setmultiset中的所有元素。
  5. 查找和統計
    find 函數:用于查找元素,set<int>::iterator it = s.find(5);multiset<int>::iterator mit = ms.find(5);分別在setmultiset中查找值為 5 的元素,并返回指向該元素的迭代器(如果元素不存在,則返回end()迭代器)。
    count 函數:在multiset中用于統計元素出現的次數,int countVal = ms.count(5);統計multiset中值為 5 的元素的個數;在set中,count函數的返回值只能是 0 或 1,因為set中元素唯一。
  6. set 和 multiset 區別
    元素唯一性:set中的元素是唯一的,不允許重復;而multiset允許元素重復出現。
    應用場景:set主要用于去重和快速查找唯一元素;multiset則更適合用于統計元素的出現次數等場景。
  7. pair 對組創建
    語法:可以使用make_pair函數或直接初始化的方式創建pair對組。例如,pair<int, string> p = make_pair(1, "one");pair<int, string> p1(2, "two");pair對組常用于在setmultimap等關聯容器中存儲鍵值對。
  8. set 容器排序
    set容器默認按照元素的升序進行排序,這是由其底層的紅黑樹結構和比較函數決定的。如果需要改變排序規則,可以自定義比較函數。例如:
struct Compare {bool operator()(int a, int b) {return a > b; // 降序排序}
};
set<int, Compare> s2;

????????通過這種方式,創建的set容器s2將按照降序對元素進行排序。

(九)map/multimap 容器

  1. 基本概念
    map是一個以鍵值對(key - value)形式存儲數據的關聯容器,其中鍵是唯一的,并且會自動按照鍵的順序進行排序,底層通常使用紅黑樹實現。這種結構使得通過鍵查找值的效率很高,適用于需要快速查找和存儲鍵值對數據的場景,比如學生成績管理系統中,以學生學號為鍵,成績為值進行存儲和查詢。
    multimapmap類似,也是存儲鍵值對,但它允許鍵重復,適用于一個鍵可以對應多個值的場景,例如一個單詞在文章中可能出現多次,需要記錄每次出現的位置,就可以使用multimap以單詞為鍵,位置為值進行存儲。
  2. 構造和賦值
    默認構造:map<int, string> m;multimap<int, string> mm;分別創建一個空的mapmultimap容器。
    拷貝構造:map<int, string> m1(m);multimap<int, string> mm1(mm);分別將已有的mapmultimap容器進行復制。
    賦值運算符重載:m = m1;mm = mm1;分別實現mapmultimap容器之間的賦值操作。
  3. 大小和交換
    size 函數:用于獲取mapmultimap中鍵值對的個數,int mapSize = m.size();int multimapSize = mm.size();
    empty 函數:用于判斷mapmultimap是否為空,bool isMapEmpty = m.empty();bool isMultimapEmpty = mm.empty();
    swap 函數:swap(m, m1);swap(mm, mm1);分別用于交換兩個map或兩個multimap容器的內容。
  1. 插入和刪除
    insert 函數:有多種插入方式。例如,使用m.insert(make_pair(1, "one"));m.insert(std::pair<int, std::string>(1, "one"));?向map容器m中插入鍵值對。在multimap中插入方式類似,如mm.insert(make_pair(1, "value1"));,由于multimap允許鍵重復,相同鍵的鍵值對會依次插入。
    erase 函數:在map中,m.erase(1);刪除鍵為 1 的鍵值對;m.erase(m.find(1));通過找到鍵 1 對應的迭代器來刪除鍵值對。在multimap中,mm.erase(1);會刪除所有鍵為 1 的鍵值對,mm.erase(mm.find(1));則只刪除找到的第一個鍵為 1 的鍵值對。
  2. 查找和統計
    find 函數:map<int, string>::iterator it = m.find(1);map?m中查找鍵為 1 的鍵值對,如果找到,it指向該鍵值對;否則it等于m.end()。在multimap中類似,multimap<int, string>::iterator mit = mm.find(1);用于查找鍵為 1 的鍵值對。
    count 函數:在map中,m.count(1)返回值只能是 0 或 1,因為鍵唯一。在multimap中,mm.count(1)用于統計鍵為 1 的鍵值對出現的次數,若存在多個鍵為 1 的鍵值對,會返回相應的數量。
  3. map 容器排序
    map默認根據鍵的升序進行排序,這基于其底層紅黑樹結構和默認比較函數。若要改變排序規則,可自定義比較函數。如:
struct KeyCompare {bool operator()(const int& a, const int& b) {return a > b; // 實現鍵的降序排序}
};
map<int, string, KeyCompare> m2;

????????如此創建的map?m2會按照鍵的降序對鍵值對進行排序。
7.?案例 - 員工分組
案例描述:假設有一個公司,需要將員工按照部門進行分組管理。每個員工有唯一的工號和所屬部門信息,要求能夠高效地存儲員工信息,并能根據部門快速查詢該部門的所有員工。此案例體現了mapmultimap在實際場景中的應用。
實現步驟:
定義員工數據結構:

struct Employee {int id;std::string name;std::string department;Employee(int i, const std::string& n, const std::string& d) : id(i), name(n), department(d) {}
};

數據錄入:使用multimap來存儲員工信息,因為一個部門可能有多個員工。例如:

multimap<std::string, Employee> employeeMap;
Employee emp1(1, "Alice", "HR");
Employee emp2(2, "Bob", "Engineering");
employeeMap.insert(make_pair("HR", emp1));
employeeMap.insert(make_pair("Engineering", emp2));

分組操作:根據部門對員工進行分組。例如,要獲取 “HR” 部門的所有員工,可以通過查找鍵 “HR” 來遍歷該部門的所有員工:

auto range = employeeMap.equal_range("HR");
for (auto it = range.first; it != range.second; ++it) {std::cout << "Employee ID: " << it->second.id << ", Name: " << it->second.name << std::endl;
}

結果輸出:將分組后的員工信息按照一定格式輸出,如上述代碼中,將 “HR” 部門的員工工號和姓名輸出顯示,方便查看和管理。

五、STL - 函數對象

(一)函數對象

  1. 概念
    函數對象是一種可調用對象,通過在類中重載()運算符來實現。它與普通函數的區別在于,函數對象可以攜帶狀態,即它可以包含成員變量來存儲額外的信息,而普通函數通常不具備這種能力。函數對象可以像普通函數一樣被調用,同時又具有類的特性,能夠進行數據封裝和繼承等操作。
  2. 使用
    在 STL 算法中,函數對象常作為參數傳遞,用于定制算法的操作邏輯。例如,在sort算法中,可以使用自定義的函數對象作為比較函數,實現特定的排序規則。假設有一個自定義的類MyComparator
class MyComparator {
public:bool operator()(const int& a, const int& b) {return a > b; // 實現降序比較}
};

在使用sort函數時,可以這樣調用:

vector<int> numbers = {1, 3, 2, 4, 5};
sort(numbers.begin(), numbers.end(), MyComparator());

這里MyComparator()作為比較函數傳遞給sort算法,使得numbers向量按照降序排列。

(二)謂詞

  1. 概念
    謂詞是一種特殊的函數對象,其返回值為bool類型,主要用于條件判斷等場景。在 STL 算法中,謂詞常用于篩選符合特定條件的元素或進行元素之間的比較。
  2. 一元謂詞
    一元謂詞是接受一個參數并返回bool值的函數對象。例如,定義一個一元謂詞IsEven來判斷一個數是否為偶數:
class IsEven {
public:bool operator()(const int& num) {return num % 2 == 0;}
};

在使用find_if算法查找向量中第一個偶數時,可以這樣應用:

vector<int> nums = {1, 3, 4, 5, 6};
auto it = find_if(nums.begin(), nums.end(), IsEven());
if (it != nums.end()) {std::cout << "First even number: " << *it << std::endl;
}

  1. 二元謂詞
    二元謂詞是接受兩個參數并返回bool值的函數對象。在排序算法中,常用二元謂詞來定義元素之間的比較規則。如前面提到的MyComparator類就是一個二元謂詞,它接受兩個int類型參數并返回比較結果,用于定義排序順序。

(三)內建函數對象

  1. 意義
    內建函數對象是 STL 提供的一些預定義的函數對象,它們涵蓋了常見的算術、關系和邏輯操作。這些內建函數對象的存在提高了代碼編寫的效率,開發者無需手動編寫這些基本操作的函數對象,直接使用即可。
  2. 算術仿函數
    加法仿函數plusplus<int>()(3, 5)返回3 + 5的結果,即 8。在accumulate算法中結合plus仿函數可用于對容器元素求和,例如:
vector<int> values = {1, 2, 3, 4, 5};
int sum = accumulate(values.begin(), values.end(), 0, plus<int>());

????????減法仿函數minusminus<int>()(5, 3)返回5 - 3的結果,即 2。可用于實現兩個數的減法操作,在一些自定義算法中可能會用到。
乘法仿函數multipliesmultiplies<int>()(3, 4)返回3 * 4的結果,即 12。在數值計算相關的算法中可能會使用到。
????????除法仿函數dividesdivides<int>()(6, 3)返回6 / 3的結果,即 2。用于實現除法運算。
????????取模仿函數modulusmodulus<int>()(7, 3)返回7 % 3的結果,即 1。在需要進行取模運算的場景中使用。
3.?關系仿函數
????????大于仿函數greatergreater<int>()(5, 3)返回true,因為5 > 3。在sort算法中,如果要對向量進行降序排序,可以使用sort(numbers.begin(), numbers.end(), greater<int>());
小于仿函數lessless<int>()(3, 5)返回true,因為3 < 5。這是sort算法默認的比較方式,用于升序排序。
????????大于等于仿函數greater_equalgreater_equal<int>()(5, 5)返回true,因為5 >= 5。在一些需要判斷大于等于關系的算法中使用。
小于等于仿函數less_equalless_equal<int>()(3, 3)返回true,因為3 <= 3。常用于條件判斷場景。
????????等于仿函數equal_toequal_to<int>()(3, 3)返回true,用于判斷兩個數是否相等。在查找算法中可能會用到,如find_if結合equal_to來查找特定值。
不等于仿函數not_equal_tonot_equal_to<int>()(3, 5)返回true,因為3 != 5。在需要判斷不相等關系的場景中使用。
4.?邏輯仿函數
????????邏輯與仿函數logical_andlogical_and<bool>()(true, false)返回false,因為true && falsefalse。在一些需要進行邏輯與運算的算法中使用,如在對容器元素進行條件篩選時。
邏輯或仿函數logical_orlogical_or<bool>()(true, false)返回true,因為true || falsetrue。用于邏輯或運算場景,例如多個條件判斷中只要有一個條件滿足的情況。
邏輯非仿函數logical_notlogical_not<bool>()(true)返回false,因為!truefalse。用于對邏輯值取反的操作。

六、STL - 常用算法

(一)常用遍歷算法

  1. for_each
    語法:for_each(iterator start, iterator end, function object)。它接受一個迭代器范圍(起始迭代器start和結束迭代器end)以及一個函數對象。
    功能:對容器中指定范圍內的每個元素逐一應用傳入的函數對象。例如,假設有一個打印整數的函數對象PrintNumber
class PrintNumber {
public:void operator()(const int& num) {std::cout << num << " ";}
};
vector<int> nums = {1, 2, 3, 4, 5};
for_each(nums.begin(), nums.end(), PrintNumber());

上述代碼會將nums向量中的每個元素依次打印出來。
應用場景:常用于對容器元素進行簡單的遍歷操作,如打印元素、對每個元素進行簡單的計算等。
2.?transform
語法:transform(iterator start, iterator end, output_iterator, function object)transform(iterator1 start, iterator1 end, iterator2 start, output_iterator, function object)。第一種形式將輸入范圍[start, end)內的元素通過函數對象進行轉換,并將結果存儲到以output_iterator開始的位置;第二種形式從兩個輸入范圍(分別以iterator1 startiterator2 start開始)中取出元素,通過函數對象進行轉換,并將結果存儲到output_iterator開始的位置。
功能:對容器元素進行轉換并存儲到新容器或原容器。例如,將一個向量中的每個元素乘以 2 并存儲到另一個向量中:

class MultiplyByTwo {
public:int operator()(const int& num) {return num * 2;}
};
vector<int> source = {1, 2, 3, 4, 5};
vector<int> result(source.size());
transform(source.begin(), source.end(), result.begin(), MultiplyByTwo());

這里MultiplyByTwo函數對象將source向量中的每個元素乘以 2,并將結果存儲到result向量中。
應用場景:在數據轉換、類型轉換等場景中廣泛應用,如將字符串向量中的所有字符串轉換為大寫形式,或者將一個數值向量中的每個元素進行特定的數學運算后存儲到新向量。

(二)常用查找算法

  1. find
    語法:find(iterator start, iterator end, value)。它在指定的迭代器范圍[start, end)內查找值為value的元素。
    功能:在容器中查找指定值。例如,在一個向量中查找值為 3 的元素:
vector<int> numbers = {1, 2, 3, 4, 5};
auto it = find(numbers.begin(), numbers.end(), 3);
if (it != numbers.end()) {std::cout << "Element 3 found at position: " << std::distance(numbers.begin(), it) << std::endl;
}

如果找到元素,find函數返回指向該元素的迭代器;否則返回end迭代器。
應用場景:常用于判斷容器中是否存在特定元素,或者獲取特定元素在容器中的位置。
2.?find_if
語法:find_if(iterator start, iterator end, predicate)。它在指定的迭代器范圍[start, end)內查找滿足謂詞predicate的第一個元素。
功能:在容器中查找滿足條件的元素。例如,查找向量中第一個大于 3 的元素:

class GreaterThanThree {
public:bool operator()(const int& num) {return num > 3;}
};
vector<int> nums = {1, 2, 4, 5, 3};
auto it1 = find_if(nums.begin(), nums.end(), GreaterThanThree());
if (it1 != nums.end()) {std::cout << "First element greater than 3: " << *it1 << std::endl;
}

應用場景:在需要按特定條件篩選元素時使用,如在一個學生成績向量中查找第一個不及格的成績。
3.?adjacent_find
語法:adjacent_find(iterator start, iterator end)adjacent_find(iterator start, iterator end, binary_predicate)。第一種形式查找相鄰且相等的元素;第二種形式使用自定義的二元謂詞查找滿足特定條件的相鄰元素。
功能:查找相鄰且相等的元素。例如,在一個向量中查找相鄰重復的元素:

vector<int> values = {1, 2, 2, 3, 4};
auto it2 = adjacent_find(values.begin(), values.end());
if (it2 != values.end()) {std::cout << "Adjacent duplicate element found: " << *it2 << std::endl;
}

如果找到相鄰重復元素,返回指向第一個重復元素的迭代器;否則返回end迭代器。
應用場景:用于檢測序列中是否存在相鄰重復的元素,在數據去重、數據校驗等場景中可能會用到。
4.?binary_search
語法:binary_search(iterator start, iterator end, value)binary_search(iterator start, iterator end, value, compare)。第一種形式在有序的迭代器范圍[start, end)內使用默認比較函數二分查找值為value的元素;第二種形式使用自定義的比較函數compare進行二分查找。
功能:在有序容器中二分查找指定值。例如,在一個有序向量中查找值為 4 的元素:

vector<int> sortedNums = {1, 2, 3, 4, 5};
bool found = binary_search(sortedNums.begin(), sortedNums.end(), 4);
if (found) {std::cout << "Element 4 found in the sorted vector." << std::endl;
}

如果找到元素,返回true;否則返回false
應用場景:在需要高效查找有序序列中的元素時使用,相比順序查找,二分查找的時間復雜度更低,適用于大規模數據的查找。
5.?count
語法:count(iterator start, iterator end, value)。它在指定的迭代器范圍[start, end)內統計值為value的元素個數。
功能:統計容器中指定值出現的次數。例如,在一個向量中統計值為 2 的元素個數:

vector<int> numbers = {1, 2, 2, 3, 2, 4};
int countVal = count(numbers.begin(), numbers.end(), 2);
std::cout << "The number 2 appears " << countVal << " times." << std::endl;

應用場景:常用于統計元素頻率,如統計一篇文章中某個單詞出現的次數。
6.?count_if
語法:count_if(iterator start, iterator end, predicate)。它在指定的迭代器范圍[start, end)內統計滿足謂詞predicate的元素個數。
功能:統計容器中滿足條件的元素個數。例如,統計向量中大于 3 的元素個數:

class GreaterThanThree {
public:bool operator()(const int& num) {return num > 3;}
};
vector<int> nums = {1, 2, 4, 5, 3, 6};
int countGreater = count_if(nums.begin(), nums.end(), GreaterThanThree());
std::cout << "The number of elements greater than 3 is: " << countGreater << std::endl;

應用場景:在需要按條件統計元素數量時使用,如統計一個

班級成績中及格人數、統計一組數據中奇數的數量等場景。

(三)常用排序算法

  1. sort
    語法:sort(iterator start, iterator end)?或?sort(iterator start, iterator end, comparator)。第一種形式使用默認的小于比較函數(less)對迭代器范圍?[start, end)?內的元素進行升序排序;第二種形式則使用自定義的比較函數?comparator?來決定排序規則。
    功能:對容器元素進行排序。例如,對一個存儲整數的向量進行升序排序:
std::vector<int> numbers = {5, 3, 7, 1, 9};
std::sort(numbers.begin(), numbers.end());

若要進行降序排序,可自定義比較函數:

struct Greater {bool operator()(const int& a, const int& b) {return a > b;}
};
std::vector<int> numbers = {5, 3, 7, 1, 9};
std::sort(numbers.begin(), numbers.end(), Greater());

應用場景:廣泛應用于各種需要對數據進行排序的場景,如對學生成績進行排名、對商品價格進行排序展示等。
2.?random_shuffle
語法:random_shuffle(iterator start, iterator end)。它對指定迭代器范圍?[start, end)?內的元素進行隨機重排。
功能:隨機打亂容器元素順序。例如,將一副撲克牌(用向量表示)的順序打亂:

std::vector<int> deck(52);
for (int i = 0; i < 52; ++i) {deck[i] = i;
}
std::random_shuffle(deck.begin(), deck.end());

應用場景:在需要隨機化數據順序的場景中使用,如游戲中的隨機發牌、隨機分組等。
3.?merge
語法:merge(iterator1 start, iterator1 end, iterator2 start, iterator2 end, output_iterator)?或?merge(iterator1 start, iterator1 end, iterator2 start, iterator2 end, output_iterator, comparator)。第一種形式將兩個有序的輸入范圍(分別由?iterator1 start?到?iterator1 end?和?iterator2 start?到?iterator2 end?定義)合并到以?output_iterator?開始的輸出范圍,使用默認的小于比較函數;第二種形式則使用自定義的比較函數?comparator?進行合并。
功能:合并兩個有序容器。例如,將兩個有序的整數向量合并成一個新的有序向量:

std::vector<int> v1 = {1, 3, 5};
std::vector<int> v2 = {2, 4, 6};
std::vector<int> result(v1.size() + v2.size());
std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), result.begin());

應用場景:在數據處理中,當需要將多個有序數據集合并成一個更大的有序數據集時使用,如合并多個有序的日志文件。
4.?reverse
語法:reverse(iterator start, iterator end)。它將指定迭代器范圍?[start, end)?內的元素順序反轉。
功能:反轉容器元素順序。例如,將一個字符串(用?string?容器表示)反轉:

std::string str = "hello";
std::reverse(str.begin(), str.end());

應用場景:在需要改變序列順序的場景中使用,如將鏈表反轉、將數字的各位順序反轉等。

(四)常用拷貝和替換算法

  1. copy
    語法:copy(iterator start, iterator end, output_iterator)。它將迭代器范圍?[start, end)?內的元素拷貝到以?output_iterator?開始的位置。
    功能:將容器元素拷貝到另一個位置。例如,將一個向量的元素拷貝到另一個向量:

std::vector<int> source = {1, 2, 3, 4, 5};
std::vector<int> destination(source.size());
std::copy(source.begin(), source.end(), destination.begin());

應用場景:常用于數據備份、容器間元素復制等場景,如將一個臨時計算結果向量復制到最終存儲向量。
2.?replace
語法:replace(iterator start, iterator end, old_value, new_value)。它將迭代器范圍?[start, end)?內所有值為?old_value?的元素替換為?new_value
功能:將容器中指定值替換為新值。例如,將一個向量中所有的 3 替換為 30:

std::vector<int> numbers = {1, 3, 2, 3, 4};
std::replace(numbers.begin(), numbers.end(), 3, 30);

應用場景:在數據修正場景中使用,如將文本中錯誤的單詞統一替換為正確的單詞。
3.?replace_if
語法:replace_if(iterator start, iterator end, predicate, new_value)。它將迭代器范圍?[start, end)?內所有滿足謂詞?predicate?的元素替換為?new_value
功能:將容器中滿足條件的值替換為新值。例如,將一個向量中所有大于 5 的元素替換為 0:

class GreaterThanFive {
public:bool operator()(const int& num) {return num > 5;}
};
std::vector<int> numbers = {1, 3, 7, 4, 8};
std::replace_if(numbers.begin(), numbers.end(), GreaterThanFive(), 0);

應用場景:在按條件修改數據時使用,如將一組成績中不及格的分數替換為補考標記。
4.?swap
語法:swap(value1, value2)。它交換兩個值?value1?和?value2?的內容。
功能:交換兩個值。例如,交換兩個整數變量的值:

int a = 5;
int b = 3;
std::swap(a, b);

在容器場景中,也可用于交換兩個容器的內容,如?std::swap(v1, v2);?交換兩個向量?v1?和?v2?的內容。
應用場景:元素交換、容器內容交換等場景,如在排序算法中用于交換元素位置,在需要快速切換兩個數據集時交換容器內容。

(五)常用算術生成算法

  1. accumulate
    語法:accumulate(iterator start, iterator end, initial_value)?或?accumulate(iterator start, iterator end, initial_value, binary_function)。第一種形式將迭代器范圍?[start, end)?內的元素累加,并加上初始值?initial_value,使用默認的加法操作;第二種形式則使用自定義的二元函數?binary_function?進行累加操作。
    功能:對容器元素進行累加求和。例如,計算一個向量中所有元素的和:

std::vector<int> numbers = {1, 2, 3, 4, 5};
int sum = std::accumulate(numbers.begin(), numbers.end(), 0);

若要進行乘法累加(即計算所有元素的乘積),可自定義二元函數:

struct Multiply {int operator()(const int& a, const int& b) {return a * b;}
};
std::vector<int> numbers = {1, 2, 3, 4, 5};
int product = std::accumulate(numbers.begin(), numbers.end(), 1, Multiply());

應用場景:數值計算場景,如計算一組數據的總和、平均值等,在金融計算、統計分析等領域有廣泛應用。
2.?fill
語法:fill(iterator start, iterator end, value)。它將迭代器范圍?[start, end)?內的所有元素填充為指定值?value
功能:將容器指定范圍填充為指定值。例如,將一個向量的所有元素初始化為 0:

std::vector<int> numbers(5);
std::fill(numbers.begin(), numbers.end(), 0);

應用場景:在初始化容器元素、重置容器內容等場景中使用,如在進行多次數據處理前,將結果容器清空并填充為初始值。

(六)常用集合算法

  1. set_intersection
    語法:set_intersection(iterator1 start, iterator1 end, iterator2 start, iterator2 end, output_iterator)?或?set_intersection(iterator1 start, iterator1 end, iterator2 start, iterator2 end, output_iterator, comparator)。第一種形式求兩個有序范圍(分別由?iterator1 start?到?iterator1 end?和?iterator2 start?到?iterator2 end?定義)的交集,并將結果存儲到以?output_iterator?開始的位置,使用默認的小于比較函數;第二種形式使用自定義的比較函數?comparator
    功能:求兩個有序集合的交集。例如,求兩個有序向量的交集:

std::vector<int> v1 = {1, 3, 5, 7};
std::vector<int> v2 = {3, 5, 7, 9};
std::vector<int> intersection;
std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(intersection));

應用場景:在需要找出兩個數據集的共同部分時使用,如找出兩個學生名單中的共同學生、兩個商品清單中的重復商品等。
2.?set_union
語法:set_union(iterator1 start, iterator1 end, iterator2 start, iterator2 end, output_iterator)?或?set_union(iterator1 start, iterator1 end, iterator2 start, iterator2 end, output_iterator, comparator)。第一種形式求兩個有序范圍的并集,并將結果存儲到以?output_iterator?開始的位置,使用默認的小于比較函數;第二種形式使用自定義的比較函數?comparator
功能:求兩個有序集合的并集。例如,求兩個有序向量的并集:

std::vector<int> v1 = {1, 3, 5};
std::vector<int> v2 = {3, 5, 7};
std::vector<int> unionSet;
std::set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(unionSet));

應用場景:在合并兩個數據集且去除重復元素時使用,如合并兩個課程列表并去除重復課程。
3.?set_difference
語法:set_difference(iterator1 start, iterator1 end, iterator2 start, iterator2 end, output_iterator)?或?set_difference(iterator1 start, iterator1 end, iterator2 start, iterator2 end, output_iterator, comparator)。第一種形式求第一個有序范圍相對于第二個有序范圍的差集(即存在于第一個范圍但不存在于第二個范圍的元素),并將結果存儲到以?output_iterator?開始的位置,使用默認的小于比較函數;第二種形式使用自定義的比較函數?comparator
功能:求兩個有序集合的差集。例如,求向量?v1?相對于向量?v2?的差集:

std::vector<int> v1 = {1, 3, 5, 7};
std::vector<int> v2 = {3, 5};
std::vector<int> difference;
std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(difference));

應用場景:在需要找出兩個數據集的差異部分時使用,如找出兩個版本軟件功能列表的新增功能(相對于舊版本)。

七、總結

??C++ 提高編程中的模板編程和 STL 為開發者提供了強大的工具集。模板編程通過類型參數化實現了代碼的高度復用,無論是函數模板還是類模板,都極大地減少了重復代碼的編寫,提高了代碼的通用性和可維護性。STL 作為一套成熟的模板庫,其六大組件相互協作,容器提供了多樣化的數據存儲結構,算法實現了豐富的數據處理操作,迭代器則作為橋梁連接了容器和算法,使得代碼能夠高效、靈活地處理各種數據場景。通過對常用容器、函數對象和常用算法的深入理解和應用,開發者能夠顯著提升 C++ 編程的效率和質量,編寫出更健壯、更高效的代碼。在實際項目開發中,合理運用這些技術能夠降低開發成本,提高軟件的性能和可擴展性,滿足日益復雜的軟件需求。因此,深入學習和掌握模板編程與 STL 是 C++ 開發者提升自身能力的關鍵路徑。

  1. copy
    語法:copy(iterator start, iterator end, output_iterator)。它將迭代器范圍?[start, end)?內的元素拷貝到以?output_iterator?開始的位置。
    功能:將容器元素拷貝到另一個位置。例如,將一個向量的元素拷貝到另一個向量:
  2. accumulate
    語法:accumulate(iterator start, iterator end, initial_value)?或?accumulate(iterator start, iterator end, initial_value, binary_function)。第一種形式將迭代器范圍?[start, end)?內的元素累加,并加上初始值?initial_value,使用默認的加法操作;第二種形式則使用自定義的二元函數?binary_function?進行累加操作。
    功能:對容器元素進行累加求和。例如,計算一個向量中所有元素的和:
  3. set_intersection
    語法:set_intersection(iterator1 start, iterator1 end, iterator2 start, iterator2 end, output_iterator)?或?set_intersection(iterator1 start, iterator1 end, iterator2 start, iterator2 end, output_iterator, comparator)。第一種形式求兩個有序范圍(分別由?iterator1 start?到?iterator1 end?和?iterator2 start?到?iterator2 end?定義)的交集,并將結果存儲到以?output_iterator?開始的位置,使用默認的小于比較函數;第二種形式使用自定義的比較函數?comparator
    功能:求兩個有序集合的交集。例如,求兩個有序向量的交集:

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

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

相關文章

C++(類模板的運用)

使用vector實現一個簡單的本地注冊登錄系統 注冊&#xff1a;將賬號密碼存入vector里面&#xff0c;注意防重復判斷 登錄&#xff1a;判斷登錄的賬號密碼是否正確 #include <iostream> #include <vector> #include <fstream> #include <sstream> usi…

【大模型】DeepSeek+藍耕MaaS平臺+海螺AI生成高質量視頻實戰詳解

目錄 一、前言 二、藍耘智能云MaaS平臺介紹 2.1 藍耘智算平臺是什么 2.2 平臺優勢 2.3 平臺核心能力 三、海螺AI視頻介紹 3.1 海螺AI視頻是什么 3.2 海螺AI視頻主要功能 3.3 海螺AI視頻應用場景 3.4 海螺AI視頻核心優勢 3.5 項目git地址 四、藍耘MaaS平臺DeepSeek海…

接口自動化學習二:session自動管理cookie

session自動管理cookie&#xff1a; cookie中的數據&#xff0c;都是session提供的 實現步驟&#xff1a; 1.創建session對象&#xff1b;my_sessionrequests.Session() 2.使用session實例&#xff0c;調用get方法&#xff0c;發送獲取驗證碼請求&#xff08;不需要提取cookie&…

C++類型轉換詳解

目錄 一、內置 轉 內置 二、內置 轉 自定義 三、自定義 轉 內置 四、自定義 轉 自定義 五、類型轉換規范化 1.static_case 2.reinterpret_cast 3.const_cast 4.dynamic_cast 六、RTTI 一、內置 轉 內置 C兼容C語言&#xff0c;在內置類型之間轉換規則和C語言一樣的&am…

QEMU源碼全解析 —— 塊設備虛擬化(17)

接前一篇文章:QEMU源碼全解析 —— 塊設備虛擬化(16) 本文內容參考: 《趣談Linux操作系統》 —— 劉超,極客時間 《QEMU/KVM源碼解析與應用》 —— 李強,機械工業出版社 《KVM實戰 —— 原理、進階與性能調優》—— 任永杰 程舟,機械工業出版社

mac 卸載流氓軟件安全助手

之前個人電腦在公司使用過一段時間&#xff0c;為了使用網線聯網安裝了公司指定的 聯軟上網助手&#xff0c;誰知安裝容易卸載難&#xff0c;后來找運維來卸載&#xff0c;輸入管理員密碼后&#xff0c;也無反應&#xff0c;最后不了了之了&#xff0c;這個毒瘤軟件長期在后臺駐…

Java 大視界 -- Java 大數據機器學習模型在智能客服多輪對話系統中的優化策略(179)

&#x1f496;親愛的朋友們&#xff0c;熱烈歡迎來到 青云交的博客&#xff01;能與諸位在此相逢&#xff0c;我倍感榮幸。在這飛速更迭的時代&#xff0c;我們都渴望一方心靈凈土&#xff0c;而 我的博客 正是這樣溫暖的所在。這里為你呈上趣味與實用兼具的知識&#xff0c;也…

極氪汽車云原生架構落地實踐

云原生架構落地實踐的背景 隨著極氪數字業務的飛速發展&#xff0c;背后的 IT 技術也在不斷更新迭代。極氪極為重視客戶對服務的體驗&#xff0c;并將系統穩定性、業務功能的迭代效率、問題的快速定位和解決視為構建核心競爭力的基石。 為快速響應用戶的需求&#xff0c;例如…

Python?判斷循環

????˙?˙? ? 判斷??常用的判斷符號(比較運算符)andor括號notin 和 not inif-elif-else循環??計數循環 forrange()函數簡易倒計時enumerate()函數zip()函數遍歷列表遍歷元組遍歷字符串遍歷字典條件循環 while提前跳轉 continue跳出循環 break能量站??判斷?? …

FreeRTOS與RT-Thread深度對比:從入門到精通的全面解析

FreeRTOS與RT-Thread深度對比&#xff1a;從入門到精通的全面解析 在嵌入式系統開發領域&#xff0c;實時操作系統(RTOS)扮演著至關重要的角色。FreeRTOS和RT-Thread作為兩款主流的開源RTOS&#xff0c;各有特色&#xff0c;適用于不同的應用場景。本文將從小白到大神的角度&a…

OpenCV 圖形API(18)用于執行兩個矩陣(或數組)的逐元素減法操作函數sub()

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 描述 計算兩個矩陣之間的逐元素差值。 sub 函數計算兩個矩陣之間的差值&#xff0c;要求這兩個矩陣具有相同的尺寸和通道數&#xff1a; dst ( I ) src…

LeetCode刷題SQL筆記

系列博客目錄 文章目錄 系列博客目錄1.distinct關鍵字 去除重復2.char_length()3.group by 與 count()連用4.date類型有個函數datediff()5.mod 函數6.join和left join的區別1. **JOIN&#xff08;內連接&#xff0c;INNER JOIN&#xff09;**示例&#xff1a; 2. **LEFT JOIN&a…

其他合成方式介紹

在 SurfaceFlinger 的 Layer 處理邏輯中&#xff0c;除了常見的 Client Composition&#xff08;GPU合成&#xff09; 和 Device Composition&#xff08;HWC合成&#xff09;&#xff0c;還存在一些特殊的合成方式&#xff0c;比如 Sideband、Solid Color 和 Display Decorati…

GraphRAG與知識圖譜

一、GraphRAG介紹 1.1 什么是 Graph RAG&#xff1f; Graph RAG&#xff08;Retrieval-Augmented Generation&#xff09;&#xff0c;是一種基于知識圖譜的檢索增強技術&#xff0c; 通過構建圖模型的知識表達&#xff0c;將實體和關系之間的聯系用圖的形式進行展示&#xff…

一個開源的 VS Code 大模型聊天插件:Light-at

這篇文章是一個開發雜談。對于有經驗的開發者來說&#xff0c;可能這個項目并不算特別復雜或者高技術&#xff0c;只是對我個人來說算一個里程碑&#xff0c;因此寫篇雜談文章記錄一下。也許也能給起步者一些參考。 項目地址&#xff1a;https://github.com/HiMeditator/light-…

SQL121 創建索引

-- 普通索引 CREATE INDEX idx_duration ON examination_info(duration);-- 唯一索引 CREATE UNIQUE INDEX uniq_idx_exam_id ON examination_info(exam_id);-- 全文索引 CREATE FULLTEXT INDEX full_idx_tag ON examination_info(tag);描述 現有一張試卷信息表examination_in…

【Pandas】pandas DataFrame set_flags

Pandas2.2 DataFrame Attributes and underlying data 方法描述DataFrame.index用于獲取 DataFrame 的行索引DataFrame.columns用于獲取 DataFrame 的列標簽DataFrame.dtypes用于獲取 DataFrame 中每一列的數據類型DataFrame.info([verbose, buf, max_cols, …])用于提供 Dat…

Linux終止進程(kill process)的一些玩法

經常運行一個程序時&#xff0c;表面上已經終止了&#xff0c;實際上還在后臺運行。一來呢&#xff0c;它可能占據端口&#xff0c;導致端口復用的時候報錯。二來呢&#xff0c;它可能占用GPU&#xff0c;讓你顯存直接少一塊。 尤其是在多進程程序&#xff0c;假如運行“python…

《比特城傳奇:公鑰、私鑰與網絡安全的守護之戰》

點擊下面圖片帶您領略全新的嵌入式學習路線 &#x1f525;爆款熱榜 88萬閱讀 1.6萬收藏 第一章&#xff1a;雙鑰之謎 比特城的清晨總是籠罩著一層薄霧&#xff0c;仿佛這座城市本身就是由無數個0和1編織而成的幻境。在這里&#xff0c;信息如同空氣般無處不在&#xff0c;但…

BGP路由協議之屬性1

公認屬性是所有 BGP 路由器都必須能夠識別的屬性 公認必遵 (Well-known Mandatory) : 必須包括在每個 Update 消息里公認任意 (Well-known Discretionary) : 可能包括在某些 Update 消息里。 可選屬性不需要都被 BGP 路由器所識別 可選過渡(OptionalTransitive) : BGP 設備不…