【C++】Stack Queue 仿函數

📝前言:
這篇文章我們來講講STL中的stack和queue。因為前面我們已經有了string、vector和list的學習基礎,所以這篇文章主要關注一些stackqueue的細節問題,以及了解一下deque(縫合怪)和priority_queue ,并且模擬實現priority_queue

🎬個人簡介:努力學習ing
📋個人專欄:C++學習筆記
🎀CSDN主頁 愚潤求學
🌄其他專欄:C語言入門基礎,python入門基礎,python刷題專欄


文章目錄

  • 一,Stack && queue
    • 1. 用vector 適配 Stack
    • 2. 用list模擬實現queue
    • 3. 簡單認識deque
  • 二,priority_queue
    • 1. 認識優先級隊列
    • 2. 仿函數
    • 3. 模擬實現priority_queue

一,Stack && queue

  1. stackqueue其實是container adaptor(容器適配器)
    在這里插入圖片描述
    在STL里面他們是用deque來適配的。也就是通過deque來封裝,內部實際上用的是deque的接口。

  2. stack.top()返回的是棧頂元素的引用,queue.front()一樣

  3. stack.pop()并不會返回值,而是直接pop掉棧頂元素,queue.pop()一樣

除了deque能做適配器以外,其他的容器也都可以,比如vector和list

1. 用vector 適配 Stack

對于Stack而言,要實現的是同一邊刪除與插入的操作,而vector里面正好有pop_back和push_back 這樣的接口。

#include<vector>namespace tr
{template<typename T>class stack{public:stack(){}void push(const T& x) { _a.push_back(x); }void pop() { _a.pop_back(); }const T& top() const { return _a.back(); }T& top() { return _a.back(); }size_t size() { return _a.size(); }bool empty() { return _a.empty(); }private:std::vector<T> _a; // 棧的底層用數組};
}

測試代碼:

#include<iostream>
#include<vector>
#include"Stack.h" using namespace std;void test_Stack() {tr::stack<int> st;st.push(1);st.push(2);st.push(3);st.push(4);st.push(5);while (!st.empty()){cout << st.top() << endl;st.pop();}cout << st.empty() << st.size() << endl;
}int main() {test_Stack();return 0;
}

注意頭文件和using namespace std;的位置問題:頭文件展開時會向上找標識符,比如“Stack.h”用了一個cout,但是using namespace std;在下面,向上找不到就會報錯編譯錯誤:“未定義標識符”


2. 用list模擬實現queue

list要滿足的要求是一邊插入一邊刪除,由于vector沒有頭刪,所以這時候選擇list是更好的

模擬實現:

#pragma once
#include<list>namespace tr
{template<typename T>class queue{public:queue() {}void push(const T& x) { _a.push_back(x); }const T& front() const { return _a.front(); }T& front() { return _a.front(); }void pop() { _a.pop_front(); } // 頭刪size_t size() { return _a.size(); }bool empty() { return _a.empty(); }private:std::list<T> _a;};}

測試代碼:

#include<iostream>
#include"Queue.h" using namespace std;void test_Queue() {tr::queue<int> ls;ls.push(1);ls.push(2);ls.push(3);ls.push(4);ls.push(5);while (!ls.empty()){cout << ls.front() << endl;ls.pop();}cout << "empty: " << ls.empty() << endl << "size: " << ls.size() << endl;
}int main() {test_Queue();return 0;
}

運行結果:
在這里插入圖片描述


3. 簡單認識deque

deque是雙端隊列,即兩邊都可以插入和刪除

deque并不是真正連續的空間,而是由一段段連續的小空間拼接而成的,實際deque類似于一個
動態的二維數組,其底層結構如下圖所示:
在這里插入圖片描述
map中控是一個指針數組,每個指針指向一個數組(每個數組大小一樣),這些數組才是存儲數據真正的地方。
迭代器由四個部分組成:

  • 給定一個“下標” x 找到容器中對應的數據:先 x / n:找到對應的數組編號,再 x % n 找到在組內的位置
  • 判斷是否到達一個數組的尾部:cur == last

deque 和 vector 以及 list 的比較:

  1. 頭插尾插效率更高
  2. 下標隨機訪問比vector差一點
  3. 中間插入數據效率低,因為要移動數據

由因為:

  1. stack和queue沒有迭代器,不需要訪問
  2. 實現stack時:deque的擴容效率比vector高
  3. 實現queue時:一次性申請一塊數組,在queue元素個數增長時,不需要想list一樣一個個申請,效率更高,且內存利用率更高

所以,stack和queue用了deque做適配器。


二,priority_queue

1. 認識優先級隊列

priority_queue:優先隊列,也在頭文件< queue > 里面
意思是:在使用top()pop()的時候會取優先級高的,默認是大的元素優先級高。(簡單來說就是降序)
底層實現時堆,而堆的底層是數組。
在這里插入圖片描述

簡單使用一下:

int main() {priority_queue<int> pq;pq.push(3);pq.push(2);pq.push(6);pq.push(1);pq.push(8);while (!pq.empty()){cout << pq.top();pq.pop();}return 0;
}

運行結果:
在這里插入圖片描述


2. 仿函數

仿函數是一個類,但是可以像調用函數一樣去調用這個類,作為回調函數使用。通過重載()來實現

仿函數使用示例:

class Adder {
public:// 重載 () 運算符int operator()(int a, int b) const {return a + b;}
};int main() {Adder adder;// 像調用函數一樣調用仿函數對象int result = adder(3, 4); // 或者用匿名對象:Adder()(3, 4) Adder()——創建匿名對象,(3 ,4)調用重載的()std::cout << "Result: " << result << std::endl;return 0;
}

3. 模擬實現priority_queue

priority_queue頭文件:

#pragma once
#include<iostream>
#include<vector>
using namespace std;template<class T>
class Less
{
public:bool operator()(const T& a, const T& b){return a < b;}
};template<class T>
class Greater
{
public:bool operator()(const T& a, const T& b){return a > b;}
};namespace tr
{template<class T, class Container = vector<T>, class Compare = Less<T>>// Compare 就是比較方法class priority_queue{public:void Adjustup(size_t child){Compare com; // 構造仿函數對象size_t parent = (child - 1) / 2;while (child > 0){if (com(_a[child], _a[parent])) // 用仿函數對象調用仿函數{std::swap(_a[child], _a[parent]);child = parent;parent = (child - 1) / 2;}else {break;}}}void Adjustdown(size_t parent){Compare com;size_t child = parent * 2 + 1;while (child < _a.size()){if (child + 1 < _a.size() && com(_a[child + 1], _a[child])){child++;}if (com(_a[child], _a[parent])) // 相當于孩子節點小于父親{std::swap(_a[child], _a[parent]);parent = child;child = parent * 2 + 1;}else {break;}}}priority_queue(){}void push(const T& x){_a.push_back(x);Adjustup(_a.size() - 1);}T& top(){return _a[0];}const T& top() const{return _a[0];}void pop(){std::swap(_a[0], _a[_a.size() - 1]);_a.pop_back();Adjustdown(0);}size_t size() { return _a.size(); }bool empty() { return _a.empty(); }private:Container _a;};};

測試代碼:

#include"priority_queue.h"
int main() {tr::priority_queue<int, vector<int>, Greater<int>> pq; // 傳入的不是less,而是Less<int>,類模板傳的是類型,函數模板傳才是參數pq.push(3);pq.push(2);pq.push(6);pq.push(1);pq.push(8);while (!pq.empty()){cout << pq.top();pq.pop();}cout << endl;return 0;
}

運行結果(大根堆,降序):
在這里插入圖片描述

補充小知識點:編譯器對模板是按需實例化,首先編譯時:只會檢查模板的大框架,不會檢查類里面函數的內部。第二,當沒有使用到類中的成員函數時,編譯器在實例化的時候就不會實例化這些函數。(所以有的時候可能類的成員函數有問題,只是沒使用到)


🌈我的分享也就到此結束啦🌈
要是我的分享也能對你的學習起到幫助,那簡直是太酷啦!
若有不足,還請大家多多指正,我們一起學習交流!
📢公主,王子:點贊👍→收藏?→關注🔍
感謝大家的觀看和支持!祝大家都能得償所愿,天天開心!!!

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

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

相關文章

[實戰] 天線陣列波束成形原理詳解與仿真實戰(完整代碼)

天線陣列波束成形原理詳解與仿真實戰 1. 引言 在無線通信、雷達和聲學系統中&#xff0c;波束成形&#xff08;Beamforming&#xff09;是一種通過調整天線陣列中各個陣元的信號相位和幅度&#xff0c;將電磁波能量集中在特定方向的技術。其核心目標是通過空間濾波增強目標方…

深圳漫云科技戶外公園實景兒童劇本殺小程序:開啟親子互動新紀元

在親子娛樂需求日益增長的當下&#xff0c;深圳漫云科技推出的戶外公園實景兒童劇本殺小程序&#xff0c;憑借其創新玩法與豐富功能&#xff0c;為親子家庭帶來全新體驗。該小程序融合戶外探險、角色扮演與邏輯推理&#xff0c;不僅滿足孩子好奇心&#xff0c;更提升其思維能力…

HOW - 如何測試 React 代碼

目錄 一、使用 React 測試庫&#xff1a;testing-library/react二、使用測試演練場&#xff1a;testing-playground.com三、使用 Cypress 或 Playwright 進行端到端測試四、使用 MSW 在測試中模擬網絡請求 一、使用 React 測試庫&#xff1a;testing-library/react testing-li…

COBOL語言的網絡安全

COBOL語言與網絡安全&#xff1a;傳統語言的新挑戰 引言 COBOL&#xff08;Common Business-Oriented Language&#xff09;是一種早期編程語言&#xff0c;最初于1959年被開發出來&#xff0c;主要用于商業、金融和行政系統的處理。盡管年代久遠&#xff0c;COBOL在大型機系…

通過世界排名第一的免費開源ERP,構建富有彈性的智能供應鏈

概述 現行供應鏈模式的結構性弱點凸顯了對整個行業進行重塑的必要性。正確策略和支持可以幫助您重塑供應鏈&#xff0c;降低成本&#xff0c;實現業務轉型。開源智造&#xff08;OSCG&#xff09;所推出的Odoo免費開源ERP解決方案&#xff0c;將供應鏈轉化為具有快速響應能力的…

Android 開發中compileSdkVersion 和 targetSdkVersion

在 Android 開發中&#xff0c;compileSdkVersion 和 targetSdkVersion 是 build.gradle 文件中的兩個關鍵配置&#xff0c;它們分別控制應用的編譯行為和運行時兼容性。以下是它們的詳細區別和用途&#xff1a; 1. compileSdkVersion&#xff08;編譯版本&#xff09; 作用&a…

Qt QComboBox 下拉復選多選

Qt 中&#xff0c;QComboBox 默認只支持單選&#xff0c;但實際使用過程中&#xff0c;我們經常會碰到需要多選的情況&#xff0c;但是通過一些直接或者曲折的方法還是可以實現的。 1、通過 QListWidget 間接實現 這種方式是網上搜索最多的一種方式&#xff0c;也是相對來說比…

Selenium自動化:玩轉瀏覽器,搞定動態頁面爬取

嘿&#xff0c;各位爬蟲愛好者和自動化達人們&#xff01;是不是經常遇到這種情況&#xff1a;信心滿滿地寫好爬蟲&#xff0c;requests一把梭&#xff0c;結果抓下來的HTML里&#xff0c;想要的數據空空如也&#xff1f;定睛一看&#xff0c;原來數據是靠JavaScript動態加載出…

天梯賽 L2-023 圖著色問題

使用vector<vector<int>> g(N)去存儲邊&#xff0c;然后每次判斷每個節點的鄰節點是不是相同的顏色&#xff0c;需要注意的是不同的顏色一定需要為K種&#xff0c;不能多也不能少。 #include<bits/stdc.h> using namespace std; int main(){int n,m,k;cin&g…

在ubuntu24上裝ubuntu22

實驗室上有一臺只裝了ubuntu24的電腦&#xff0c;但是項目要求在22上進行 搞兩個ubuntu系統&#xff01; 步驟一&#xff1a;制作22的啟動盤 步驟二&#xff1a;進入bios安裝界面 步驟三&#xff1a;選擇try or install ubuntu 步驟四&#xff1a;選擇try ubuntu 步驟五&…

【PVR Review】《Review of Deep Learning Methods for Palm Vein Recognition》

[1]譚振林,劉子良,黃藹權,等.掌靜脈識別的深度學習方法綜述[J].計算機工程與應用,2024,60(06):55-67. 文章目錄 1、Background and Motivation2、數據采集3、掌脈圖像預處理3.1、ROI提取算法3.2、圖像濾波與增強 4、掌脈識別算法4.1、基于深度學習的方法4.2、其他方法 5、融合識…

【CSP】202403-1詞頻統計

文章目錄 算法思路1. 數據結構選擇2. 輸入處理3. 統計出現的文章數4. 輸出結果 代碼示例代碼優化 樣例輸入 4 3 5 1 2 3 2 1 1 1 3 2 2 2 2 3 2樣例輸出 2 3 3 6 2 2算法思路 1. 數據結構選擇 vector<int>&#xff1a;用于存儲每篇文章的單詞列表&#xff08;可能包含…

Docker基礎1

本篇文章我將從系統的知識體系講解docker的由來和在linux中的安裝下載 隨后的文章會介紹下載鏡像、啟動新容器、登錄新容器 如需轉載&#xff0c;標記出處 docker的出現就是為了節省資本和服務器資源 當企業需要一個新的應用程序時&#xff0c;需要為它買臺全新的服務器。這樣…

Linux系統學習Day04 阻塞特性,文件狀態及文件夾查詢

知識點4【文件的阻塞特性】 文件描述符 默認為 阻塞 的 比如&#xff1a;我們讀取文件數據的時候&#xff0c;如果文件緩沖區沒有數據&#xff0c;就需要等待數據的到來&#xff0c;這就是阻塞 當然寫入的時候&#xff0c;如果發現緩沖區是滿的&#xff0c;也需要等待刷新緩…

vue 3 從零開始到掌握

vue3從零開始一篇文章帶你學習 升級vue CLI 使用命令 ## 查看vue/cli版本&#xff0c;確保vue/cli版本在4.5.0以上 vue --version ## 安裝或者升級你的vue/cli npm install -g vue/cli ## 創建 vue create vue_test ## 啟動 cd vue_test npm run servenvm管理node版本&#…

Mysql專題篇章

一、事務的四大特性&#xff1f; 1、原子性&#xff1a;是指事務包含的所有操作要么全部成功&#xff0c;要么全部失敗回滾。 2、一致性&#xff1a;是指一個事務執行之前和執行之后都必須處于一致性狀態。比如a與b賬戶共有100塊&#xff0c;兩人之間轉賬之后無論成功還是失敗…

CAD插件實現:自動遞增編號(前綴、后綴、位數等)——CADc#實現

cad中大量輸入一定格式的遞增編號時&#xff0c;可用插件實現&#xff0c;效果如下&#xff1a; ①本插件可指定數字位數、起始號碼、加前綴、后綴、文字顏色等&#xff08;字體樣式和文字所在圖層為cad當前圖層和當前字體樣式&#xff09;。 ②插件采用Jig方式&#xff0c;即…

k8s1.24升級1.28

0、簡介 這里只用3臺服務器來做一個簡單的集群&#xff0c;當前版本是1.24.17目標升級到1.28.17 地址主機名192.168.160.40kuber-master-1192.168.160.41kuber-master-2192.168.160.42kuber-node-1 因為1.24已經更換過了容器運行時&#xff0c;所以之后的升級相對就會簡單&am…

4.3-2 jenkins

一.登錄jenkins 二.修改密碼 三.配置節點 新建節點 編輯節點名稱 編輯節點配置 激活節點 將jar下載到指定的路徑 再到dos命令下的路徑 E:\az\wx 執行 配置節點成功 四. 安全設置中&#xff0c;勾選代理 五.新建項目 編輯項目名稱 編輯項目執行的 路徑&#xff1a;C:\Users\Ad…

js對象與數組的互轉

js對象與數組的互轉 文章目錄 js對象與數組的互轉一、數組轉對象1.使用forEach,for in,es6展開運算符,assign2. 使用 Object.fromEntries()3. 將數組轉為鍵值對對象4. 使用 reduce()4. 數組元素為對象時提取屬性 二、對象轉數組1. 提取鍵/值/鍵值對2. 轉換為特定結構的數組 三、…