C++入門 容器適配器 / stack queue模擬實現

?目錄

容器適配器

deque的原理介紹

stack模擬實現

queue模擬實現

priority_queue模擬實現

仿函數


容器適配器

適配器是一種設計模式(設計模式是一套被反復使用的、多數人知曉的、經過分類編目的、代碼設計經驗的總 結),該種模式是將一個類的接口轉換成客戶希望的另外一個接口。AI給出這樣解釋:

可以這樣理解:通過適配器模式,可以將不兼容的接口正常運作。


?STL標準庫中stack和queue的底層結構

雖然stack和queue中也可以存放元素,但在STL中并沒有將其劃分在容器的行列,而是將其稱為容器適配 器,這是因為stack和隊列只是對其他容器的接口進行了包裝,STL中stack和queue默認使用deque,比如:


那么這里的deque是什么東西呢?

deque的原理介紹

deque(雙端隊列):是一種雙開口的"連續"空間的數據結構,雙開口的含義是:可以在頭尾兩端進行插入和刪除操作,且時間復雜度為O(1),與vector比較,頭插效率高,不需要搬移元素;與list比較,空間利用率比較高。

?deque并不是真正連續的空間,而是由一段段連續的小空間拼接而成的,實際deque類似于一個動態的二維數組。

?我們假設一個buff是10個int大小的空間數組,map中存放了每個buff數組的地址,buff數組用來存放數據,可以理解他從中間開始利用空間,向左右擴容

?我們可以理解為他在map中間進行插入刪除操作:

  1. 與vector比較,deque的優勢是:頭部插入和刪除時,不需要搬移元素,效率特別高,而且在擴容時,也不需要搬移大量的元素,因此其效率是必vector高的。
  2. 與list比較,其底層是連續空間,空間利用率比較高,不需要存儲額外字段。

但是,deque有一個致命缺陷:不適合遍歷,因為在遍歷時,deque的迭代器要頻繁的去檢測其是否移動到某段小空間的邊界,導致效率低下,而序列式場景中,可能需要經常遍歷,因此在實際中,需要線性結構時,大多數情況下優先考慮vector和list,deque的應用并不多,而目前能看到的一個應用就是,STL用其作為stack和queue的底層數據結構。?

為什么選擇deque作為stack和queue的底層默認容器?我們給出了以下兩點原因:

  1. stack和queue不需要遍歷(因此stack和queue沒有迭代器),只需要在固定的一端或者兩端進行操作。
  2. 在stack中元素增長時,deque比vector的效率高(擴容時不需要搬移大量數據);queue中的元素增長 時,deque不僅效率高,而且內存使用率高。

stack模擬實現

目前為止,我們已經了解了兩種模式:

  1. 適配器模式 -- 封裝轉換
  2. 迭代器模式 -- 封裝統一訪問方式(數據結構訪問都可以用)

接下來試著通過運用適配器來模擬實現stack和queue:

//Stack.h
#pragma oncenamespace bit
{template<class T, class Container = deque<T>>class stack{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_back();}const T& top(){return _con.back();}bool empty(){return _con.empty();}size_t size(){_con.size();}private:Container _con;};
}

?我們只需要定義一個適配器類型的成員變量_con,他默認可以使用push_back,pop_back等常規接口,直接利用接口實現操作即可。stack用vector和list都可以實現,測試代碼如下:

void test_stack()
{//bit::stack<int, vector<int>> s;//bit::stack<int, list<int>> s; bit::stack<int, deque<int>> s;  //bit::stack<int> s; //不傳第二個參數默認使用deques.push(1);s.push(2);s.push(3);s.push(4);while (!s.empty()){cout << s.top() << " ";s.pop();}cout << endl;
}

queue模擬實現

//Queue.h
#pragma oncenamespace bit
{// deque list// 不支持vectortemplate<class T, class Container = deque<T>>class queue{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_front();// 這樣就可以支持vector了,但是效率就很低了//_con.erase(_con.begin());}T& back(){return _con.back();}T& front(){return _con.front();}bool empty(){return _con.empty();}size_t size(){_con.size();}private:Container _con;};
}

注意:queue不支持vector適配器,原因是vector沒有pop_front的接口,如果要實現要用erase接口,但是頭刪完后面所有數據要往前挪,消耗時間太大,不建議這樣做。測試代碼如下:

void test_queue()
{bit::queue<int> q;//bit::queue<int,list<int>> q;// 不支持//bit::queue<int, vector<int>> q;q.push(1);q.push(2);q.push(3);q.push(4);while (!q.empty()){cout << q.front() << " ";q.pop();}cout << endl;
}

priority_queue模擬實現

仿函數

在實現之前先了解仿函數的概念:重載了operator()的類

特點:參數個數和返回值根據需求確定,不固定,很靈活

?通過這個概念可以實現STL庫里的greater和less同等效果的仿函數。

//priority_queue.h
#pragma oncenamespace bit
{template<class T>class myless{public:bool operator()(const T& x, const T& y){return x < y;}};template<class T>class mygreater{public:bool operator()(const T& x, const T& y){return x > y;}};template<class T, class Container = vector<T>, class Comapre = myless<T>>class priority_queue{public:priority_queue() = default;template <class InputIterator>priority_queue(InputIterator first, InputIterator last){while (first != last){_con.push_back(*first);++first;}for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--){adjust_down(i);}}void adjust_up(int child){Comapre comfunc;int parent = (child - 1) / 2;while (child > 0){//if (_con[parent] < _con[child])if (comfunc(_con[parent], _con[child]))//if (comfunc.operator()(_con[parent], _con[child])){swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}void push(const T& x){_con.push_back(x);adjust_up(_con.size() - 1);}void adjust_down(int parent){Comapre comfunc;size_t child = parent * 2 + 1;while (child < _con.size()){//if (child+1 < _con.size() && _con[child] < _con[child+1] )if (child + 1 < _con.size() && comfunc(_con[child], _con[child + 1])){++child;}//if (_con[parent] < _con[child])if (comfunc(_con[parent], _con[child])){swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjust_down(0);}const T& top(){return _con[0];}size_t size(){return _con.size();}bool empty(){return _con.empty();}private:Container _con;};
}

我們可以通過顯式調用greater仿函數來實現小堆,測試代碼如下:

void test_priority_queue()
{//vector<int> v = { 3,2,7,6,0,4,1,9,8,5 };//priority_queue<int> q1(v.begin(), v.end());int a[] = { 3,2,7,6,0,4,1,9,8,5 };// 默認是大堆//bit::priority_queue<int> q1(a, a+sizeof(a)/sizeof(int));// 小堆bit::priority_queue<int, vector<int>, bit::mygreater<int>> q1(a, a + sizeof(a) / sizeof(int));while (!q1.empty()){cout << q1.top() << " ";q1.pop();}cout << endl;
}

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

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

相關文章

深度學習Week19——學習殘差網絡和ResNet50V2算法

文章目錄 深度學習Week18——學習殘差網絡和ResNet50V2算法 一、前言 二、我的環境 三、論文解讀 3.1 預激活設計 3.2 殘差單元結構 四、模型復現 4.1 Residual Block 4.2 堆疊Residual Block 4.3. ResNet50V2架構復現 一、前言 &#x1f368; 本文為&#x1f517;365天深度學…

Kubernetes k8s 命名空間 namespace 介紹以及應用 資源限額配置

目錄 命名空間 什么是命名空間&#xff1f; namespace應用場景 namespacs使用案例分享 namespace資源限額 文檔中的YAML文件配置直接復制粘貼可能存在格式錯誤&#xff0c;故實驗中所需要的YAML文件以及本地包均打包至網盤 鏈接&#xff1a;https://pan.baidu.com/s/1qv8Tc…

Python中異步事件觸發

1、問題背景 在Python中&#xff0c;我想創建一個由事件生成控制流程的類結構。為此&#xff0c;我做了以下工作&#xff1a; class MyEvent: EventName_FunctionName {}classmethoddef setup(cls, notificationname, functionname):if notificationname in MyEvent.EventN…

ONLYOFFICE 8.1版本震撼來襲,讓辦公更高效、更智能

官網鏈接&#xff1a; 在線PDF查看器和轉換器 | ONLYOFFICE 在線辦公套件 | ONLYOFFICE 隨著科技的不斷發展&#xff0c;辦公軟件已經成為現代企業提高工作效率、實現信息共享的重要工具。在我國&#xff0c;一款名為ONLYOFFICE的在線辦公套件受到了越來越多企業的青睞。今天…

golang中的類型轉換那些事

由于golang是一門強類型的語言&#xff0c; 所以我們在golang的開發中不可避免的會對一些數據類型進行手動轉換&#xff0c;以適應我們的業務需求。 golang中類型轉換的途徑大致有4種&#xff0c;強制轉換&#xff0c;類型斷言&#xff0c;類型匹配 還有使用strconv包中提供的…

[TensorFlow-Lite][深度學習]【快速簡介-1】

前言&#xff1a; 很多場景下面我們需要需要把我們的深度學習模型部署到Android,IOS 手機上面. Google 通過TensorFlow Lite 提供了對應的解決方案. 目錄&#xff1a; 端側部署優點 硬件支持 性能 應用案例 一 端側部署優點 1; 很多場景下面&#xff1a; 無網絡,數據無法…

Hadoop 遠程 debug

Hadoop 命令行 在執行 hadoop fs 命令行之前&#xff0c;先執行以下命令&#xff1a; export HADOOP_CLIENT_OPTS"-Xdebug -Xrunjdwp:transportdt_socket,servery,suspendy,address8000"

昇思25天學習打卡營第10天|基于MindSpore實現BERT對話情緒識別

基于MindSpore實現BERT對話情緒識別 模型簡介數據集模型構建模型驗證模型推理自定義推理數據集 模型簡介 BERT全稱是來自變換器的雙向編碼器表征量&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;&#xff0c;它是Google于2018年末開發并發…

HTML超鏈接和錨鏈接

HTML超鏈接和錨鏈接 一、定義 HTML的超鏈接&#xff08;Hyperlink&#xff09;用于在網頁之間創建鏈接&#xff0c;使用戶可以點擊這些鏈接來導航到其他頁面或資源。 二、基本語法 1、語法 HTML中的超鏈接使用a標簽來定義 <a href"URL">鏈接文本</a&g…

yolov8實戰——yolov8TensorRT部署(python推理)(保姆教學)

yolov8實戰——yolov8TensorRT部署&#xff08;python推理&#xff09;&#xff08;保姆教學&#xff09; 一 、準備好代碼和環境安裝TensorRt下載代碼和安裝環境 部署和推理構建ONNX構建engine無torch推理torch推理 最近用到yolov8&#xff0c;但是尋找了一圈才找到了yolov8最…

[SAP ABAP] 版本管理

版本管理是指軟件開發過程中各種程序代碼、配置文件以及說明文檔等文件變更的管理 生成版本 版本管理 對比版本 點擊上述版本管理即可進行版本對比操作 補充擴展 我們可以使用事務碼SE10對傳輸請求進行創建、修改、刪除、合并以及更改所有者等操作 使用事務碼SCC1進行不同cl…

3D生成模型TripoSR完美搭建流程,包含所有問題解決方案!

最近需要使用3D生成模型,無意中看到了TripoSR,覺得效果還行,于是打算在Linux系統上部署一下,結果遇到很多坑,在這里寫一下詳細的部署流程和部署過程中遇到的問題。 下面是TripoSR的源碼地址。 GitHub - VAST-AI-Research/TripoSRContribute to VAST-AI-Research/TripoSR…

java-Linkedlist源碼分析

## 深入分析 Java 中的 LinkedList 源碼 LinkedList 是 Java 集合框架中的一個重要類&#xff0c;它基于雙向鏈表實現&#xff0c;提供了高效的插入和刪除操作。與 ArrayList 不同&#xff0c;LinkedList 的結構使其在特定操作上有更優的性能表現。本文將詳細分析 LinkedList …

android 進程,線程調度的區別

一 分析&#xff1a; 進程和線程在調度上有什么不同呢&#xff1f;當有一個task去占用指定的資源時候叫進程&#xff0c;當有多個task去共享使用這些資源時候&#xff0c;這個task和之后的task都叫線程&#xff08;最初這個task叫主線程&#xff09;而linux調度主要調的就是cp…

【Portswigger 學院】文件上傳

教程和靶場來源于 Burpsuite 的官網 Portswigger&#xff1a;File upload vulnerabilities - PortSwigger 原理與危害 很多網站都有文件上傳的功能&#xff0c;比如在個人信息頁面允許用戶上傳圖片作為頭像。如果網站應用程序對用戶上傳的文件沒有針對文件名、文件類型、文件內…

前端基礎:JavaScript(篇一)

目錄 JavaScript概述 JavaScript歷史&#xff1a; 須知&#xff1a; 基本語法 變量 代碼 運行 數據類型 1、數值型(number)&#xff1a; 代碼 運行 2、布爾型(boolean)&#xff1a; 代碼 運行 3、字符串型&#xff1a; 代碼 運行 4、 undefined類型 代碼…

TCP的pop網絡模式

TCP的pop網絡模式 1、tcp連接的狀態有以下11種 CLOSED&#xff1a;關閉狀態LISTEN&#xff1a;服務端狀態&#xff0c;等待客戶端發起連接請求SYN_SENT&#xff1a;客戶端已發送同步連接請求&#xff0c;等待服務端相應SYN_RECEIVED&#xff1a;服務器收到客戶端的SYN請請求&…

MySQL 基本語法講解及示例(下)

第六節&#xff1a;如何檢索資料 在本節中&#xff0c;我們將介紹如何使用SQL語句檢索數據庫中的資料&#xff0c;具體包括選擇特定列、排序、條件過濾以及組合排序等操作。我們以一個名為student的表格為例&#xff0c;演示不同的檢索方法。 初始表格 student student_idname…

修復harbor的/account/sign-in\?globalSearch=b不登錄可以查詢鏡像的問題

Nginx的location指令不能直接匹配查詢參數&#xff0c;所以需要通過其他方式來處理。這里是一個使用if指令結合查詢參數來實現的方法。該方法會在請求路徑中帶有特定查詢參數時返回404。 使用if指令匹配查詢參數 打開Nginx配置文件&#xff1a; sudo vim /etc/nginx/sites-ava…

Python中frozenset,秒變不可變集合,再也不用擔心多線程了!

目錄 1、Frozenset基礎介紹 ?? 1.1 Frozenset定義與創建 1.2 不可變集合特性 1.3 與Set的區別對比 2、Frozenset操作實踐 ?? 2.1 初始化與添加元素嘗試 2.2 成員測試: in & not in 2.3 集合運算: 并集、交集、差集 2.4 使用場景示例: 字典鍵、函數參數默認值 …