【C++】STL-priority_queue

目錄

1、priority_queue的使用

2、實現沒有仿函數的優先級隊列

3、實現有仿函數的優先級隊列

3.1 仿函數

3.2 真正的優先級隊列

3.3 優先級隊列放自定義類型

1、priority_queue的使用

priority_queue是優先級隊列,是一個容器適配器,不滿足先進先出的特點,而是優先級高的先出,默認的適配器是vector,底層是一個堆,默認是大堆

priority_queue是可以進行迭代器區間初始化的

void test_priority_queue1()
{vector<int> v = { 3,2,7,6,0,4,1,9,8,5 };priority_queue<int> q1;for (auto& e : v)q1.push(e);while (!q1.empty()){cout << q1.top() << " ";q1.pop();}cout << endl;
}
void test_priority_queue2()
{vector<int> v = { 3,2,7,6,0,4,1,9,8,5 };priority_queue<int> q1(v.begin(), v.end());while (!q1.empty()){cout << q1.top() << " ";q1.pop();}cout << endl;
}

可以用數組直接初始化?

void test_priority_queue3()
{int v[10] = {3,2,7,6,0,4,1,9,8,5};priority_queue<int> q1(v, v + 10);while (!q1.empty()){cout << q1.top() << " ";q1.pop();}cout << endl;
}

上面3段代碼的結果都是相同的,都是9 8 7 6 5 4 3 2 1 0,因為默認是建大堆

2、實現沒有仿函數的優先級隊列

namespace cxf
{template<class T,class Container = std::vector<T>>class priority_queue{public:// 建大堆void adjust_up(int child){int parent = (child - 1) / 2;while (child > 0){if (_con[parent] < _con[child]){std::swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else break;}}void adjust_down(int parent){int child = parent * 2 + 1;while (child < _con.size()){if (child + 1 < _con.size() && _con[child] < _con[child + 1]){++child;}if (_con[parent] < _con[child]){std::swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else break;}}// 強制編譯器生成默認的構造函數,因為下面有迭代器區間初始化,這樣沒辦法用默認構造函數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 push(const T& x){_con.push_back(x);adjust_up(_con.size() - 1);}void pop(){std::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;};
}

上面是建大堆的優先級隊列,當要建小堆時,需要在adjust_up和adjust_up中將<改成>,這樣是十分麻煩的,為例能夠在不修改代碼的情況下完成建小堆,所以引入了仿函數的概念

3、實現有仿函數的優先級隊列

3.1 仿函數

仿函數就是重載了operatror()的類,類的對象可以像調用函數一樣使用

operator()的特點是參數個數和返回值個數可以根據需求來定,很靈活,所以有很多用法

若用class來定義仿函數的類要加public,所以通常會用struct來定義仿函數

根據仿函數就可以來實現一個既可建大堆,又可建小堆的優先級隊列

3.2 真正的優先級隊列

namespace cxf
{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 = std::vector<T>, class Comapre = myless<T>>class priority_queue{public: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])){std::swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else break;}}void adjust_down(int parent){Comapre comfunc;int 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])){std::swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else break;}}// 強制編譯器生成默認的構造函數,因為下面有迭代器區間初始化,這樣沒辦法用默認構造函數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 push(const T& x){_con.push_back(x);adjust_up(_con.size() - 1);}void pop(){std::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;};
}

priority_queue的第三個模板參數就是仿函數?

在STL庫中的priority_queue來建小堆

3.3 優先級隊列放自定義類型

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;
}
int main()
{priority_queue<Date> q1;q1.push(Date(2022, 9, 9));q1.push(Date(2022, 9, 10));q1.push(Date(2022, 9, 11));while (!q1.empty()){cout << q1.top() << endl;q1.pop();}return 0;
}

結果是正確的,因為只要這個自定義類型是能夠比較大小的,都能使用優先級隊列

但是若比較的不是這個自定義類型,而是這個自定義類型的指針,則會出現隨機結果

int main()
{priority_queue<Date*> q1;q1.push(new Date(2022, 9, 9));q1.push(new Date(2022, 9, 10));q1.push(new Date(2022, 9, 11));while (!q1.empty()){cout << *q1.top() << endl;q1.pop();}return 0;
}

此時是錯誤的,并且每次運行程序結果也不一定都相同。因為less比較的是Date*,是根據地址比較的,而new出來的地址是隨機的,所以幾次的運行結果也會不同。而且這個比較從邏輯上就是錯誤的,因為不應該使用對象的地址去比較,應該使用對象的值去比較

所以可以自己寫一個仿函數,達到想要的目的

struct PDateLess
{bool operator()(Date* p1, Date* p2){return *p1 < *p2;}
};
int main()
{priority_queue<Date*, vector<Date*>, PDateLess> q1;q1.push(new Date(2022, 9, 9));q1.push(new Date(2022, 9, 10));q1.push(new Date(2022, 9, 11));while (!q1.empty()){cout << *q1.top() << endl;q1.pop();}return 0;
}

此時就正確的

所以仿函數不僅可以支持比較大小,還可以支持修改比較邏輯,如果默認的比較邏輯不是想要的或者不支持比較大小,都可以通過仿函數來控制。

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

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

相關文章

Spring Boot配置文件properties/yml/yaml

一、Spring Boot配置文件簡介 &#xff08;1&#xff09;名字必須為application,否則無法識別。后綴有三種文件類型&#xff1a; properties/yml/yaml&#xff0c;但是yml和yaml使用方法相同 &#xff08;2&#xff09; Spring Boot 項?默認的配置文件為 properties &#xff…

【單片機畢業設計選題24041】-基于STM32的水質檢測系統

系統功能: 系統上電后顯示“歡迎使用水質檢測系統請稍后”兩秒后進入正常顯示頁面。 第一頁面第一行顯示“系統狀態信息”&#xff0c;第二行顯示溫度和PH值信息&#xff0c;第三行顯示 渾濁度信息&#xff0c;第四行顯示TDS值信息。 第一頁面下的按鍵操作&#xff1a; 短…

Kotlin中的類

類初始化順序 constructor 里的參數列表是首先被執行的&#xff0c;緊接著是 init 塊和屬性初始化器&#xff0c;最后是次構造函數的函數體。 主構造函數參數列表firstProperty 初始化第一個 init 塊secondProperty 初始化第二個 init 塊次構造函數函數體 class Example const…

英語動詞時態

英語動詞時態總結 動詞時態一般進行完成完成進行現在一般現在時態動詞原形/動詞原形s&#xff08;第三人稱單數&#xff09;eat/eats現在進行時態助動詞be的變位動詞的現在分詞am/is/are eating現在完成時態助動詞have的變位動詞的過去分詞has/have eaten現在完成進行時態have…

SSE代替輪詢?

什么是 SSE SSE&#xff08;Server-Sent Events&#xff0c;服務器發送事件&#xff09;&#xff0c;為特定目的而擴展的 HTTP 協議&#xff0c;用于實現服務器向客戶端推送實時數據的單向通信。如果連接斷開&#xff0c;瀏覽器會自動重連&#xff0c;傳輸的數據基于文本格式。…

力扣(2024.07.01)

1. 84——柱狀圖中最大的矩形 給定 n 個非負整數&#xff0c;用來表示柱狀圖中各個柱子的高度。每個柱子彼此相鄰&#xff0c;且寬度為 1 。 求在該柱狀圖中&#xff0c;能夠勾勒出來的矩形的最大面積。 標簽&#xff1a;棧&#xff0c;數組&#xff0c;單調棧&#xff08;目…

面試題--SpringBoot

SpringBoot SpringBoot 是什么(了解) 是 Spring 的子項目,主要簡化 Spring 開發難度,去掉了繁重配置,提供各種啟動器,可以 讓程序員很快上手,節省開發時間. SpringBoot 的優點(必會) SpringBoot 對上述 Spring 的缺點進行的改善和優化&#xff0c;基于約定優于配置的思想&am…

rust嵌入式開發2024

老的rust embedded book 其實過時了. 正確的姿勢是embassy 入手. 先說下以前rust寫嵌入怎么教學小白的. 第一步,從這里 svd2rust 工具,自己生成庫第二部,有了這個庫,相當于就有了pac外設訪問文件,然后其實就可以搞起來了. 那么為啥不好搞了. 因為太亂了. 小白喜歡你告我咋弄…

[python][Anaconda]使用jupyter打開F盤或其他盤文件

jupyter有一個非常不好的體驗&#xff0c;就是不能在界面切換到其他盤來打開文件。 使用它&#xff0c;比較死板的操作是要先進入文件目錄&#xff0c;再運行jupyter。 以Windows的Anaconda安裝了jupyter lab或jupyter notebook為例。 1&#xff0c;先運行Anaconda Prompt 2&…

[Day 22] 區塊鏈與人工智能的聯動應用:理論、技術與實踐

大數據與AI的關聯性 引言 大數據和人工智能&#xff08;AI&#xff09;是當今科技界的兩大熱門話題。這兩者的聯繫愈加緊密&#xff0c;相互影響和促進&#xff0c;形成了一個強大的技術生態系統。大數據提供了豐富的數據來源&#xff0c;而AI則利用這些數據來訓練和優化算法…

基于OpenCV與Keras的停車場車位自動識別系統

本項目旨在利用計算機視覺技術和深度學習算法&#xff0c;實現對停車場車位狀態的實時自動識別。通過攝像頭監控停車場內部&#xff0c;系統能夠高效準確地辨認車位是否被占用&#xff0c;為車主提供實時的空閑車位信息&#xff0c;同時為停車場管理者提供智能化的車位管理工具…

網優小插件_基于chrome瀏覽器Automa插件編寫抓取物業點信息小工具

日常在無線網絡優化&#xff0c;經常需要提取某一地市&#xff0c;某個屬性物業點信息&#xff08;物業點名稱、地址、及經緯度信息&#xff09;&#xff0c;本文介紹基于chrome瀏覽器Automat插件開發自動化工具&#xff0c;利用百度地圖經緯度拾取網資源開發一個抓取物業點基本…

2024年了cv還有什么可以卷的嗎?

2024年&#xff0c;計算機視覺&#xff08;CV&#xff09;領域依然有很多可以探索和創新的方向。以下是一些潛在的研究熱點&#xff1a; 自監督學習與無監督學習&#xff1a;繼續探索如何在沒有大量標注數據的情況下訓練高性能的模型&#xff0c;尤其是跨模態自監督學習和多任務…

為什么這幾年參加PMP考試的人越來越多

參加PMP認證的人越來越多的原因我認為和社會發展、職場競爭、個人提升等等方面有著不小的關系。國際認證與國內認證的性質、發展途徑會有一些區別&#xff0c;PMP引進到中國二十余年&#xff0c;報考人數持增長狀態也是正常的。 具體可以從下面這幾個點來展開論述。 市場競爭…

全面掌握 Postman 數據導入與導出:詳細指南

Postman 是一款廣泛使用的 API 開發工具&#xff0c;它提供了豐富的功能來幫助開發者測試、開發和維護 API。其中&#xff0c;數據導入和導出是 Postman 中非常重要的功能之一&#xff0c;它們允許用戶將工作從一個環境遷移到另一個環境&#xff0c;或者與團隊成員共享配置。本…

面試專區|【88道測試工具考核高頻題整理(附答案背誦版)】

常用的監控工具有哪些&#xff1f; 常用的監控工具有以下幾種&#xff1a; Zabbix&#xff1a;是一個基于WEB界面的提供分布式系統監視以及網絡監視功能的企業級開源解決方案&#xff0c;能監視各種網絡參數&#xff0c;保證服務器系統的安全運營&#xff0c;并提供靈活的通知…

Rakis: 免費基于 P2P 的去中心化的大模型

是一個開源的&#xff0c;完全在瀏覽器中運行的去中心化 AI 推理網絡&#xff0c;用戶無需服務器&#xff0c;打開即可通過點對點網絡使用 Llama-3、Mistral、Gemma-2b 等最新開源模型。 你可以通過右上角的 Scale Worker &#xff0c;下載好模型后掛機就能作為節點加入到這個…

JVM線上監控環境搭建Grafana+Prometheus+Micrometer

架構圖 一: SpringBoot自帶監控Actuator SpringBoot自帶監控功能Actuator&#xff0c;可以幫助實現對程序內部運行情況監控&#xff0c;比如監控內存狀況、CPU、Bean加載情況、配置屬性、日志信息、線程情況等。 使用步驟&#xff1a; 1. 導入依賴坐標 <dependency><…

比武招親大會

題目 郭靖夫婦在襄陽城舉辦比武招親大會&#xff0c;為女兒尋覓佳婿。比賽一共三關&#xff0c;第一關比武功。你身懷九陽神功&#xff0c;楊過使出了絕學黯然銷魂掌依然敗給了你。來自蒙古的耶律齊也不是你的對手&#xff0c;黃蓉吃驚與你的武功之高&#xff0c;打心底里為女…

海外報紙媒體投放形式分為哪些?傳播當中有什么優勢-大舍傳媒

國外報紙媒體投放新聞稿作為一種傳統而有效的傳播方式&#xff0c;依然在現代媒體環境中保持著其獨特的價值和權威性。以下幾點闡述了報紙媒體宣發的幾個關鍵方面&#xff0c;特別是當通過專業機構如大舍傳媒進行操作時&#xff1a; 權威性和公信力&#xff1a;報紙作為歷史悠久…