【落羽的落羽 C++】stack和queue、deque、priority_queue、仿函數

文章目錄

  • 一、stack和queue
    • 1. 概述
    • 2. 使用
    • 3. 模擬實現
  • 二、deque
  • 三、priority_queue
    • 1. 概述和使用
    • 2. 模擬實現
  • 四、仿函數

一、stack和queue

1. 概述

我們之前學習的vector和list,以及下面要認識的deque,都屬于STL的容器(containers)組件。而stack和queue,屬于STL的配置器(或稱為配接器)(adapters)組件,或者歸類為容器配置器(container adapters),它們可以修飾容器的接口而呈現出全新的容器性質,即stack的“先進后出”和queue的“先進先出”特點。

2. 使用

stack的所有元素的進出都必須符合“先進后出”的條件,queue的所有元素的進出都必須符合“先進先出”的條件。換句話說,只有stack的棧頂元素和queue的隊頭元素才有機會被移除,因此stack和queue不提供遍歷的功能,也不提供迭代器。

除此之外,stack和queue的功能和使用也都很好理解了,之前我們已經學過棧和隊列。

  • stack:
函數聲明接口說明
stack()構造空的棧
empty()檢測棧是否為空
size()返回棧中元素個數
top()返回棧頂元素的引用
push()在棧頂入棧
pop()將棧頂元素出棧

使用演示:
在這里插入圖片描述

  • queue:
函數聲明接口說明
queue()構造空的隊列
empty()檢測隊列是否為空
size()返回隊列中元素個數
front()返回隊頭元素的引用
back()返回隊尾元素的引用
push()在隊尾入隊列
pop()將隊頭元素出隊列

使用演示:
在這里插入圖片描述

3. 模擬實現

STL庫中的stack和queue的模板實際上有兩個模板類型:
在這里插入圖片描述
在這里插入圖片描述
第一個就是要存儲的數據類型了。第二個代表它們所修飾的容器類型,前面說過,它們不是獨立的容器,而是容器配置器,要依靠別的容器才能實現它們,這就是第二個模板參數的意義。我們可以用vector或list來實現出stack和queue,如stack<int, vector<int>>queue<char, list<char>>,我們在上層使用stack和queue時是感受不到vector或list的區別的。不論是哪種容器,都有push、pop、front、back、empty等相關操作,得以再封裝成stack和queue的功能。
模板參數也是可以有缺省值的,我們能看到STL標準庫中的stack和queue的Container模板類型默認給了deque,deque也是一種容器,我們一會再介紹它。

除了這一點,stack和queue的模擬實現就很簡單了,遵循它們的特性就好:

namespace lydly
{template<class T, class Container = deque<T>>class queue{private:Container _con;public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_front();}T& front(){return _con.front();}const T& front() const{return _con.front();}T& back(){return _con.back();}const T& back() const{return _con.back();}bool empty() const{return _con.empty();}size_t size() const{return _con.size();}};template<class T, class Container = deque<T>>class stack{private:Container _con;public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_back();}T& top(){return _con.back();}const T& top() const{return _con.back();}bool empty() const{return _con.empty();}size_t size() const{return _con.size();}};
}

二、deque

關于deque,簡單了解就好。
對比一下vector和list的優缺點:

容器優點缺點
vector支持下標隨機訪問、CPU高速緩存命中率高頭部或中部插入刪除數據效率低、擴容有一定成本,存在一定浪費
list任意位置插入刪除數據效率高、不用擴容,按需申請空間,不存在浪費不支持下標隨機訪問、CPU高速緩存命中率低

可見,vector和queue都有各自的優缺點,deque包含了兩種容器的優點,是一種雙向開口的線性連續空間

在這里插入圖片描述
deque有一個中控器,存放著指向不同節點的指針,每一個節點是一個緩沖區buffer,是一個數組用于存放數據。執行尾插時,就在當前buffer的尾部插入數據,若當前buffer已滿,就去中控器的下一個節點指向的buffer的第一個位置存放;執行頭插時,要倒著看,當前buffer頭部沒有空間,就去中控器的上一個節點指向的buffer的最后一個位置存放,再頭插一次就存放到倒數第二個位置,以此類推。頭刪和尾刪也是一樣的道理。

在這里插入圖片描述
deque并不是真正完全連續的空間,而是由一段段連續的小空間拼接而成的,實際deque類似一個動態的二維數組,deque的迭代器的結構就更為復雜了。

所以,deque與vector相比,頭部插入效率更高,不需要挪動元素;與list相比,空間利用率更高。但是,deque不適合遍歷,因為在遍歷時迭代器需要頻繁檢測每一個buffer是否到達邊界,導致效率低下。而在序列式場景中,可能經常需要遍歷,所以實際需要線性數據結構時,大多數情況下優先考慮vector和list,deque的應用并不多,目前能看到的一個應用就是STL用它作為stack和queue的底層數據結構。
而STL選擇deque作為stack和queue的底層,主要原因也是stack和queue不需要遍歷,只在固定的一端或兩端進行操作,以及deque結合vector和list的優點了。

三、priority_queue

1. 概述和使用

priority_queue,意為優先級隊列,是queue的一種,帶有權值觀念,其內的元素并非按照入隊列的順序排列,而是按照元素的權值排列,默認權值較高的元素排在前面。
舉個栗子:
在這里插入圖片描述
有沒有發現,優先級隊列其實就是我們之前學過的堆。
在這里插入圖片描述
優先級隊列默認使用vector作為其底層存儲數據的容器,在vector上又使用了堆算法將vector中元素構造成堆的結構,因此priority_queue就是堆,所有需要用到堆的場景,都可以考慮使用優先級隊列。默認情況下,優先級隊列是大堆。

函數聲明接口說明
priority_queue()構造空的優先級隊列
empty()檢測優先級隊列是否為空
size()返回優先級隊列中元素個數
top()返回優先級隊列中的最大(最小)元素,即堆頂元素
push()在優先級隊列中插入元素
pop()刪除優先級隊列中的最大(最小)元素,即堆頂元素

2. 模擬實現

既然優先級隊列就是堆,那么實現優先級隊列也就和實現堆道理類似了:
傳送門:https://blog.csdn.net/2402_86681376/article/details/145808942?spm=1011.2415.3001.5331(堆的講解
要用到的向上調整算法、向下調整算法,我們都學習過了。

namespace lydly
{template<class T, class Container = vector<T>>class priority_queue{private:Container _con;public:priority_queue(){}void push(const T& x){_con.push_back(x);adjustup(_con.size() - 1);}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjustdown(0);}const T& top() const{return _con[0];}bool empty() const{return _con.empty();}size_t size() const{return _con.size();}private:void adjustup(int child){int parent = (child - 1) / 2;while (child > 0){if (_con[parent] < _con[child]){swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void adjustdown(size_t parent){size_t child = parent * 2 + 1;while (child < _con.size()){if (child + 1 < _con.size() && _con[child] < _con[child + 1]){++child;}if (_con[parent] < _con[child]){swap(_con[child], _con[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}};
}

問題來了,我們想讓優先級隊列降序排列元素,再重載一次·未必太麻煩了,怎么辦呢?這里就需要用到仿函數。

四、仿函數

在STL標準庫中,我們看到優先級隊列的模板參數中還有一個Compare,這個就是仿函數。
在這里插入圖片描述
仿函數是一種類對象,顧名思義,它可以“模仿函數”,允許用戶“以模板參數來指定所要采取的策略”。在priority_queue中,它的第三個模板類型參數就是仿函數,默認給了一個less,less其實是這樣的:

template<class T>
class less
{
public:bool operator()(const T& x, const T& y){return x < y;}
};

less是一個類,less<typename Container::value_type>就是一個匿名對象,它的里面重載了(),這樣一來,倘若有less<T> Com;那我們就可以寫出Com(a, b),(a,b是T類型的)這個表達式的意思就是a < b
舉一反三,STL中還有greater的仿函數:

template<class T>
class greater
{
public:bool operator()(const T& x, const T& y){return x > y;}
};

倘若有greater<T> Com;那我們就可以寫出Com(a, b),這個表達式的意思就是a > b

大堆和小堆的區別在于AdjustUp和AdjustDown中幾處<或>的不同,有了上面的兩種仿函數,我們就能在創建優先級隊列時根據需要,模板參數傳less或greater,區分大堆和小堆。具體是<還是>,就可以依靠傳的是less還是greater來分別。STL的仿函數中的less和greater,就可以傳給priority_queue的模板:
在這里插入圖片描述

我們的模擬實現也按照這個思路來完成:

namespace lydly
{template<class T>class less{public:bool operator()(const T& x, const T& y){return x < y;}};template<class T>class greater{public:bool operator()(const T& x, const T& y){return x > y;}};template<class T, class Container = vector<T>, class Compare = less<T>>class priority_queue{private:Container _con;public:priority_queue(){}void push(const T& x){_con.push_back(x);adjustup(_con.size() - 1);}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjustdown(0);}const T& top() const{return _con[0];}bool empty() const{return _con.empty();}size_t size() const{return _con.size();}private:void adjustup(int child){//構造一個less或greater的對象Compare com;int parent = (child - 1) / 2;while (child > 0){if (com(_con[parent], _con[child])){swap(_con[child], _con[parent]);// child = parent;parent = (child - 1) / 2;}else{break;}}}void adjustdown(size_t parent){//構造一個less或greater的對象Compare com;size_t child = parent * 2 + 1;while (child < _con.size()){if (child + 1 < _con.size() && com(_con[child], _con[child + 1])){++child;}if (com(_con[parent], _con[child])){swap(_con[child], _con[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}};
}

關于less,我們還可能會遇到其他情況:

  • 當想要比較的是自定義類型時,就需要這個自定義類型中重載<和>運算符,這一點很好理解。
  • 當傳入指針時,一般我們應該是想要比較的是指向的內容,但如果只把less寫成剛才那樣,會被解析成直接比較兩個地址的值。這時,需要寫成這樣:
template<class T>
class less<T*>
{
public:bool operator()(const T* const & x, const T* const & y){return *x < *y;}
};

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

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

相關文章

用生活例子通俗理解 Python OOP 四大特性

讓我們用最生活化的方式&#xff0c;結合Python代碼&#xff0c;來理解面向對象編程的四大特性。 1. 封裝&#xff1a;像使用自動售貨機 生活比喻&#xff1a; 你只需要投幣、按按鈕&#xff0c;就能拿到飲料 不需要知道機器內部如何計算找零、如何運送飲料 如果直接打開機…

軟件安全(三)實現后門程序

如下是一個經典的后門程序 #define _WINSOCK_DEPRECATED_NO_WARNINGS 1 #include<WinSock2.h> #include<windows.h> #include<iostream> #pragma comment(lib, "ws2_32.lib")int main() {//初始化網絡環境WSADATA wsaData;int result WSAStartup…

深入理解高性能網絡通信:從內核源碼到云原生實踐

深入理解高性能網絡通信&#xff1a;從內核源碼到云原生實踐 前言 隨著互聯網業務規模的高速增長&#xff0c;服務端網絡通信能力成為系統性能的核心瓶頸。如何支撐百萬級連接、在極限場景下實現低延遲高吞吐&#xff1f;本篇博客將圍繞Linux通信機制內核剖析、性能調優實戰、…

從實戰看軟件測試與質量管理:方法、過程與質量的全景解讀

作為一名高級軟件測試工程師&#xff0c;在過往多個大型系統項目的測試工作中&#xff0c;我深刻體會到&#xff1a;軟件測試不僅是產品質量的“守門員”&#xff0c;更是項目成功的“加速器”。今天這篇文章&#xff0c;我將站在實戰角度&#xff0c;結合具體案例&#xff0c;…

Megatron系列——流水線并行

內容總結自&#xff1a;bilibili zomi 視頻大模型流水線并行 注&#xff1a;這里PipeDream 1F1B對應時PP&#xff0c;Interleaved 1F1B對應的是VPP 1、樸素流水線并行 備注&#xff1a; &#xff08;1&#xff09;紅色三個圈都為空泡時間&#xff0c;GPU沒有做任何計算 &am…

在Web應用中集成Google AI NLP服務的完整指南:從Dialogflow配置到高并發優化

在當今數字化客服領域,自然語言處理(NLP)技術已成為提升用戶體驗的關鍵。Google AI提供了一系列強大的NLP服務,特別是Dialogflow,能夠幫助開發者構建智能對話系統。本文將詳細介紹如何在Web應用中集成這些服務,解決從模型訓練到高并發處理的全套技術挑戰。 一、Dialogflow…

Wi-Fi網絡角色及功能詳解

在 Wi-Fi 網絡中&#xff0c;不同的角色和組件協同工作以實現無線通信。以下是 Wi-Fi 中的主要角色及其功能&#xff1a; 1. 基礎設施模式&#xff08;Infrastructure Mode&#xff09; 這是最常見的 Wi-Fi 網絡架構&#xff0c;包含以下核心角色&#xff1a; 接入點&#xff…

密碼學--希爾密碼

一、實驗目的 1、通過實現簡單的古典密碼算法&#xff0c;理解密碼學的相關概念 2、理解明文、密文、加密密鑰、解密密鑰、加密算法、解密算法、流密碼與分組密碼等。 二、實驗內容 1、題目內容描述 ①定義分組字符長度 ②隨機生成加密密鑰&#xff0c;并驗證密鑰的可行性 …

[C++] 一個線程打印奇數一個線程打印偶數

要求開辟兩個線程打印從0-100的數&#xff0c;一個線程打印奇數一個線程打印偶數&#xff0c;要求必須按照1,2,3,4,5,6…100這種按照順序打印 使用std::shared_mutex的版本 #ifndef PrintNumber2_H_ #define PrintNumber2_H_#include <shared_mutex>class PrintNumber2…

MySQL全量、增量備份與恢復

目錄 數據備份 一、數據備份類型 二、常見備份方法 擴展&#xff1a;GTID與XtraBackup ?一、GTID&#xff08;全局事務標識符&#xff09;? ?1. 定義與核心作用? ?2. GTID在備份恢復中的意義? ?3. GTID配置與啟用? ?二、XtraBackup的意義與核心價值? ?1. 定…

木馬查殺篇—Opcode提取

【前言】 介紹Opcode的提取方法&#xff0c;并探討多種機器學習算法在Webshell檢測中的應用&#xff0c;理解如何在實際項目中應用Opcode進行高效的Webshell檢測。 Ⅰ 基本概念 Opcode&#xff1a;計算機指令的一部分&#xff0c;也叫字節碼&#xff0c;一個php文件可以抽取出…

DeepSeek-R1-Distill-Qwen-1.5B代表什么含義?

DeepSeek?R1?Distill?Qwen?1.5B 完整釋義與合規須知 一句話先行 這是 DeepSeek?AI?把自家?R1?大模型?的知識&#xff0c;通過蒸餾壓縮進一套 Qwen?1.5B 架構 的輕量學生網絡&#xff0c;并以寬松開源許可證發布的模型權重。 1?|?名字逐段拆解 片段意義備注DeepSee…

Megatron系列——張量并行

本文整理自bilibili Zomi視頻 1、行切分和列切分 注意&#xff1a; &#xff08;1&#xff09;A按列切分時&#xff0c;X無需切分&#xff0c;split復制廣播到A1和A2對應設備即可。最后Y1和Y2需要拼接下&#xff0c;即All Gather &#xff08;2&#xff09;A按行切分時&#…

java agent技術

從JDK1.5之后引入了java angent技術 Java Agent 是一種強大的技術&#xff0c;它允許開發者在 JVM 啟動時或運行期間動態地修改類的字節碼&#xff0c;從而實現諸如性能監控、日志記錄、AOP&#xff08;面向切面編程&#xff09;等功能 java agent依賴于Instrumentation API&…

LLaMA Factory 深度調參

注意&#xff0c;本文涵蓋從基礎調參到前沿研究的完整知識體系&#xff0c;建議結合具體業務場景靈活應用。一篇“參考文獻”而非“可運行的代碼”。https://github.com/zysNLP/quickllm 初始指令&#xff1a; llamafactory-cli train \--stage sft \--do_train True \--mode…

Linux驅動:驅動編譯流程了解

要求 1、開發板中的linux的zImage必須是自己編譯的 2、內核源碼樹,其實就是一個經過了配置編譯之后的內核源碼。 3、nfs掛載的rootfs,主機ubuntu中必須搭建一個nfs服務器。 內核源碼樹 解壓 tar -jxvf x210kernel.tar.bz2 編譯 make x210ii_qt_defconfigmakeCan’t use ‘…

Redis集群模式、持久化、過期策略、淘汰策略、緩存穿透雪崩擊穿問題

Redis四種模式 單節點模式 架構??&#xff1a;單個Redis實例運行在單臺服務器。 ??優點??&#xff1a; ??簡單??&#xff1a;部署和配置容易&#xff0c;適合開發和測試。 ??低延遲??&#xff1a;無網絡通信開銷。 ??缺點??&#xff1a; ??單點故障??&…

1.2 函數

函數的本質是描述變量間的依賴關系&#xff1a;??一個變量&#xff08;自變量&#xff09;的變化會唯一確定另一個變量&#xff08;因變量&#xff09;的值??。 ??基本構成??&#xff1a;通過符號&#xff08;如YF(X)&#xff09;表達規則&#xff0c;X輸入 → F處理 …

2025數字孿生技術全景洞察:從工業革命到智慧城市的跨越式發展

引言 數字孿生技術&#xff0c;這一融合物理世界與虛擬鏡像的革新性工具&#xff0c;正以驚人的速度重塑產業格局。2025年&#xff0c;中國數字孿生市場規模預計達214億元&#xff0c;工業制造領域占比超40%&#xff0c;其技術深度與行業落地成果令人矚目。本文將結合最新數據與…

RabbitMQ 工作模式

RabbitMQ 一共有 7 中工作模式&#xff0c;可以先去官網上了解一下&#xff08;一下截圖均來自官網&#xff09;&#xff1a;RabbitMQ 官網 Simple P&#xff1a;生產者&#xff0c;要發送消息的程序&#xff1b;C&#xff1a;消費者&#xff0c;消息的接受者&#xff1b;hell…