【C++】優先級隊列+反向迭代器

priority_queue的介紹

通常用堆來實現,能在O(log n)的時間復雜度內插入和提取最高(或最低)優先級的元素。
在這里插入圖片描述

  1. 優先隊列是一種容器適配器,根據嚴格的弱排序標準,它的第一個元素總是它所包含的元素中最大的(默認情況)。
  2. 此上下文類似于堆,在堆中可以隨時插入元素,并且只能檢索最大堆元素(優先隊列中位于頂部的元素)。
  3. 優先隊列被實現為容器適配器,容器適配器即將特定容器類封裝作為其底層容器類,queue提供一組特定的成員函數來訪問其元素。元素從特定容器的“尾部”彈出,其稱為優先隊列的頂部。
  4. 底層容器可以是任何標準容器類模板,也可以是其他特定設計的容器類。容器應該可以通過隨機訪問迭代器訪問,并支持以下操作
    empty():檢測容器是否為空
    size():返回容器中有效元素個數
    front():返回容器中第一個元素的引用
    push_back():在容器尾部插入元素
    pop_back():刪除容器尾部元素
  5. 標準容器類vector和deque滿足這些需求。默認情況下,如果沒有為特定的priority_queue類實例化指定容器類,則使用vector。
  6. 需要支持隨機訪問迭代器,以便始終在內部保持堆結構。容器適配器通過在需要時自動調用算法函數make_heap、push_heap和pop_heap來自動完成此操作。

弱排序標準是一種在數學和編程中用于定義元素之間排序關系的二元關系。它要求關系滿足以下三個主要性質:
1.自反性:對于任何元素a,a與自身是相等的。
2.傳遞性:如果a小于b,且b小于c,則a小于c。
3.連通性:對于任何兩個元素a和b,要么a小于b,要么b小于a

priority_queue的使用

1.默認情況下是大堆,其底層按照less比較;若創建小堆,將第三個模板參數換成greater的比較方式;
2.如果在priority_queue中放自定義類型的數據,用戶需要在自定義類型中提供> 或者< 的重載。

數組中第k大的元素

在這里插入圖片描述

大堆方法:第三個模板參數直接使用less排序,利用前置–的特性,k–
將優先級隊列中的前k-1個元素刪除掉
在這里插入圖片描述

小堆方法:第三個模板參數要傳入greater排序函數,運用topk問題思想,創建前k個元素的小堆,從數組的第k個元素開始遍歷。如果當前元素大于堆頂元素(堆頂是最小值),則移除堆頂元素,并將當前元素加入堆。最后,堆頂元素即為數組中第k大的元素。
在這里插入圖片描述

priority_queue的模擬實現

仿函數

又稱函數對象,是類模板,通過重載()運算符,使得類模板的對象可以像函數一樣被調用。
區分:函數模板要傳對象,類模板要傳參數是類型,不能加括號
在這里插入圖片描述

向下調整

void Adjustdown(int parent)
{Compare com;int child = 2 * parent + 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[parent], _con[child]);parent = child;child = 2 * parent + 1;}elsebreak;}
}

通過比較器 Compare 確定堆的類型。用于從父節點開始向下調整堆結構,確保堆的性質得到滿足。
作用:維護堆的性質,確保插入或移除操作后堆的結構仍然有效。
應用場景:插入新元素后或移除堆頂元素后調用。

向上調整

void Adjustup(int child)
{Compare com;int parent = (child - 1) / 2;while (child > 0){if (com(_con[parent],_con[child])){swap(_con[parent], _con[child]);child = parent;parent = (child - 2) / 2;}else{break;}}
}

通過比較器 Compare 確定堆的類型。用于從子節點開始向上調整堆結構,確保堆的性質得到滿足。
作用:維護堆的性質,確保插入新元素后堆的結構仍然有效。
應用場景:插入新元素后調用。

構造函數

在這里插入圖片描述

復制元素:將迭代器范圍內的所有元素復制到內部容器 _con 中。
構建堆:從最后一個非葉子節點開始,運用向下調整法逐步向上調整堆結構,確保堆的性質得到滿足。

刪除

在這里插入圖片描述

交換堆頂元素與末尾元素,然后調用尾刪函數,或者直接size–實現刪除功能,再從堆頂即下標為0的位置開始向下調整來滿足堆序

插入

在這里插入圖片描述

插入新元素后,從最后索引位置size()-1來向上調整滿足堆序。

自定義類測試(日期類)

	class Date{public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}bool operator<(const Date& d)const{return (_year < d._year) ||(_year == d._year && _month < d._month) ||(_year == d._year && _month == d._month && _day < d._day);}bool operator>(const Date& d)const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}friend ostream& operator<<(ostream& _cout, const Date& d);private:int _year;int _month;int _day;};ostream& operator<<(ostream& _cout, const Date& d){_cout << d._year << "-" << d._month << "-" << d._day;return _cout;}struct LessPDate{bool operator()(const Date* p1, const Date* p2){return *p1 < *p2;}};
}
void test_priority_queue2()
{priority_queue<Date*, vector<Date*>, LessPDate> pq;pq.push(new Date(2024, 6, 7));pq.push(new Date(2025, 1, 19));pq.push(new Date(2025, 10, 24));while (!pq.empty()){cout << *pq.top() << " ";pq.pop();}cout << endl;//測試仿函數的調用,與日期類無關Less<int>lessfunc;cout << lessfunc(10, 24) << endl;cout << lessfunc.operator()(10, 24) << endl;
}

優先級隊列的定義:priority_queue<Date*, vector<Date*>, LessPDate> 表示優先級隊列中存儲的是 Date 類型的指針,底層容器是 vector,比較器是 LessPDate。
插入元素:通過 push 方法插入三個 Date 對象。
輸出元素:通過 while 循環依次輸出隊列中的元素,直到隊列為空。
在這里插入圖片描述

整體代碼

#pragma once
#include<vector>
#include<functional>//仿函數/函數對象
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;}
};namespace ee
{template<class T,class Container=vector<T>, class Compare=less<T>>class priority_queue{private:void Adjustdown(int parent){Compare com;int child = 2 * parent + 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[parent], _con[child]);parent = child;child = 2 * parent + 1;}elsebreak;}}void Adjustup(int child){Compare com;int parent = (child - 1) / 2;while (child > 0){if (com(_con[parent],_con[child])){swap(_con[parent], _con[child]);child = parent;parent = (child - 2) / 2;}else{break;}}}public:priority_queue(){}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--){Adjustdown(i);}}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();Adjustdown(0);}void push(const T& x){_con.push_back(x);Adjustup(_con.size() - 1);}const T& top(){return _con[0];}bool empty(){return _con.empty();}size_t size(){return _con.size();}private:Container _con;};

反向迭代器

顧名思義是用于反向遍歷的工具。反向迭代器通常通過容器的 rbegin() 和 rend() 方法獲取。rbegin() 返回指向容器最后一個元素下一個位置的反向迭代器(end),而 rend() 返回指向容器第一個元素的反向迭代器(begin)。

namespace ee
{template<class Iterator,class ref,class ptr>struct ReverseIterator{typedef ReverseIterator<Iterator, ref, ptr> self;Iterator _it;ReverseIterator(Iterator it):_it(it){ }ref operator*(){Iterator tmp = _it;return *(--tmp);}ptr operator->(){//返回解引用對象的地址return &(operator*());}self& operator++()//前置++{--_it;return *this;}self& operator--(){++_it;return *this;}bool operator!=(const self& s)const{return _it != s._it;}};
}

一般采用鏡像對稱的方式來模擬實現,即rbegin對應end,rend對應begin。
在重載*運算符時需要注意解引用的是迭代器當前指向的前一個位置,因為rbegin是最后元素的下一個位置,有可能為空會造成非法訪問,或者是哨兵位頭節點的位置。
++和–分別實現自減和自增的操作來滿足反向迭代器的功能。

若不使用鏡像對稱的方式來模擬實現反向迭代器,那么*操作符的重載就要跟隨發生變化。

vector中適配

記得包含ReverseIterator.h頭文件即可

在這里插入圖片描述
在這里插入圖片描述

list中適配

在這里插入圖片描述
在這里插入圖片描述

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

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

相關文章

mysql鏡像創建docker容器,及其可能遇到的問題

前提&#xff0c;已經弄好基本的docker服務了。 一、基本流程 1、目錄準備 我自己的資料喜歡放在 /data 目錄下&#xff0c;所以老規矩&#xff1a; 先進入 /data 目錄&#xff1a; cd /data 創建 mysql 目錄&#xff1a; mkdir mysql 2、鏡像查找 docker search hub.ra…

快速記憶法,提高知識點背誦效率

戰國七雄&#xff1a;齊秦 韓趙魏 燕楚 諧音記憶&#xff1a;齊秦 喊趙薇 演出 五等爵位&#xff1a;公侯 伯子 男 記憶方法&#xff1a;公猴 脖子 藍 安卓應用&#xff1a;記憶宮殿APP 記憶 腦力訓練&#xff0c;中小學各學科知識點速記&#xff0c;單詞趣味記憶&#xff0c…

從零開始學java--泛型(1)

泛型 學生成績可能是數字類型&#xff0c;也可能是字符串類型&#xff0c;如何存放可能出現的兩種類型呢&#xff1a; public class Score {String name;String id;Object value; //因為Object是所有類型的父類&#xff0c;因此既可以存放Integer也能存放Stringpublic Score…

pdf轉latex

Doc2X&#xff08;https://doc2x.noedgeai.com/&#xff09; Doc2X 是一個由 NoEdgeAI 提供的在線工具&#xff0c;主要用于將 PDF 文件&#xff08;尤其是學術論文、報告等文檔&#xff09;轉換為 LaTeX 格式。LaTeX 是一種高質量排版系統&#xff0c;廣泛應用于學術界和出版…

Visual Studio 2022 UI機器學習訓練模塊

VS你還是太超標了&#xff0c;現在機器學習都不用寫代碼了嗎&#xff01;&#xff01; 右鍵項目解決方案&#xff0c;選擇機器學習模型

無公網實體服務器加裝多個操作系統供多個用戶互不打擾使用_part1

背景介紹 因筆者業務需求&#xff0c;入手了一個實體服務器&#xff0c;但為了避免出現在一個操作系統中搭建編程環境后有許多相關的進程和服務&#xff0c;拖慢日常的使用&#xff0c;也能讓其他人短期使用&#xff0c;更好的利用服務器的性能&#xff0c;讓服務器專注于“什…

運動規劃實戰案例 | 基于四叉樹分解的路徑規劃(附ROS C++/Python仿真)

目錄 1 為什么需要四叉樹&#xff1f;2 基于四叉樹的路徑規劃2.1 分層抽象2.2 路圖搜索2.3 動態剪枝 3 算法仿真3.1 ROS C算法仿真3.2 Python算法仿真 1 為什么需要四叉樹&#xff1f; 路徑規劃的本質是在給定環境中尋找從起點到終點的最優或可行路徑&#xff0c;其核心挑戰在…

docker快捷打包腳本(ai版)

直接進入主題&#xff1a; 用這個腳本前提是你本地可以拉鏡像倉庫的鏡像&#xff0c;并且在 本地有了&#xff0c;然后將所有的鏡像tag寫在一個文件中&#xff0c;和下面docker_tags.txt 對應&#xff0c;文件叫什么&#xff0c;腳本里對應改什么&#xff0c;給小白說的 #!/bi…

WinMerge下載及使用教程(附安裝包)

文章目錄 一、WinMerge安裝步驟1.WinMerge下載&#xff1a;2.解壓&#xff1a;3.啟動&#xff1a; 二、WinMerge使用步驟1.添加文件或文件夾2.查看差異3.格式選擇 WinMerge v2.16.36 是一款免費開源的文件與文件夾比較、合并工具&#xff0c;能幫您快速找出差異&#xff0c;提高…

Jmeter性能測試之生成測試報告

結構 測試計劃 測試計劃是頂級的層級?錄的結構&#xff0c; 那么在這樣的?錄結構中&#xff0c;??可以包含很多線程組 線程組 線程組我們可以簡單的理解為postman測試?具??的collection&#xff0c;那么在整體線程組??&#xff0c;可以添加很多的測試 ?例 簡單控…

CSS中的inline-flex與flex的區別

在CSS中&#xff0c;flex 和 inline-flex 都是用于實現彈性布局&#xff08;Flexbox&#xff09;的顯示屬性&#xff0c;但它們在布局行為上有所不同。 flex 屬性會使元素表現為塊級彈性容器&#xff0c;這意味著元素會在頁面上占據一整行的空間&#xff0c;無論其內部內容的大…

Linux的那些基礎常用命令匯總

目錄 前言&#xff1a; 用戶命令&#xff1a; 管理后臺作業命令&#xff1a; 文件目錄操作命令&#xff1a; 運維高頻使用命令&#xff1a; 磁盤管理以及文件系統命令: 用戶、組操作命令&#xff1a; 權限控制命令&#xff1a; 網絡配置命令&#xff1a; 軟件管理命令…

高效深度學習lecture03

lecture_03 **剪枝&#xff1a;**pruning basically turns a dense neural network into a sparse neural network. you can remove those redundant synapses, and also you can remove those redundant neurons. 剪枝的本質上是將稠密的神經網絡轉變成稀疏的神經網絡&#…

Nextjs15 實戰 - React Notes 項目初始化

current branch 對應如下文檔 redis ioredis 本專欄內容均可在Github&#xff1a;notes_01 找到 一、效果 完整項目使用技術棧&#xff1a; Nextjs15 MySQL Redis Auth Prisma i18n strapi Docker vercel 二、修改根布局和其他頁面 修改 app/page.tsx&#xff1a…

Flutter PopupMenuButton 深度解析:從入門到架構級實戰

在移動應用交互設計中&#xff0c;上下文菜單如同隱形的魔法師&#xff0c;在有限屏幕空間中優雅地擴展操作維度。作為Flutter框架中的核心交互組件&#xff0c;PopupMenuButton絕非簡單的菜單觸發器&#xff0c;其背后蘊含著Material Design的交互哲學、聲明式UI的架構智慧以及…

C++——清明

#include <iostream> #include <cstring> #include <cstdlib> #include <unistd.h> #include <sstream> #include <vector> #include <memory> #include <ctime>using namespace std;class Weapon; // 前置聲明class Hero{ pr…

es --- 集群數據遷移

目錄 1、需求2、工具elasticdump2.1 mac安裝問題解決 2.2 elasticdump文檔 3、遷移 1、需求 遷移部分新集群沒有的索引和數據 2、工具elasticdump Elasticdump 的工作原理是將輸入發送到輸出 。兩者都可以是 elasticsearch URL 或 File 2.1 mac安裝 前置&#xff1a;已經安裝…

鴻蒙開發_ARKTS快速入門_語法說明_組件聲明_組件手冊查看---純血鴻蒙HarmonyOS5.0工作筆記010

然后我們來看如何使用組件 可以看到組件的組成 可以看到我們使用的組件 然后看一下組件的語法.組件中可以使用子組件. 然后組件中可以有參數,來修改組件的樣式等 可以看到{},這種方式可以設置組件參數,當然在下面. 的方式也可以的 然后再來

【GEE學習筆記】報錯解決:Sentinel-2 數據集分為 L1C(大氣頂層)和 L2A(地表反射率),如何選擇波段進行去云處理?

【GEE學習筆記】報錯解決&#xff1a;Sentinel-2 數據集分為 L1C&#xff08;大氣頂層&#xff09;和 L2A&#xff08;地表反射率&#xff09;&#xff0c;如何選擇波段進行去云處理&#xff1f; 【GEE學習筆記】報錯解決&#xff1a;Sentinel-2 數據集分為 L1C&#xff08;大…

OpenVLA-OFT——微調VLA時加快推理的三大關鍵設計:支持動作分塊的并行解碼、連續動作表示以及L1回歸(含輸入靈活化及對指令遵循的加強)

前言 25年3.26日&#xff0c;這是一個值得紀念的日子&#xff0c;這一天&#xff0c;我司「七月在線」的定位正式升級為了&#xff1a;具身智能的場景落地與定制開發商 &#xff0c;后續則從定制開發 逐步過渡到 標準產品化 比如25年q2起&#xff0c;在定制開發之外&#xff0…