[數據結構與算法] 優先隊列 | 最小堆 C++

下面是關于 C++ 中 std::priority_queue 的詳細說明,包括初始化、用法和常見的應用場景。


什么是 priority_queue

priority_queue(優先隊列)是 C++ 標準庫中的一個容器適配器。它和普通隊列(queue)最大的不同在于,元素的出隊順序不是根據它們入隊的順序(先進先出),而是根據它們的優先級

默認情況下,priority_queue 是一個大頂堆(Max-Heap),意味著優先級最高的元素是值最大的元素。每次調用 top() 都會返回當前隊列中最大的元素。

  • 底層實現:通常使用**堆(Heap)**數據結構來實現,這使得它能以對數時間復雜度(O(log n))插入元素和刪除最大(或最小)的元素。
  • 頭文件:使用前需要包含頭文件 <queue>
#include <iostream>
#include <queue>
#include <vector>
#include <functional> // 包含 std::greater 和 std::less

1. priority_queue 的初始化

priority_queue 的模板定義如下:

template <class T, class Container = std::vector<T>, class Compare = std::less<typename Container::value_type>>
class priority_queue;
  • T: 存儲的元素類型。
  • Container: 用于存儲元素的底層容器,默認為 std::vector<T>。必須是支持隨機訪問迭代器和 front(), push_back(), pop_back() 等操作的序列容器,例如 std::vectorstd::deque
  • Compare: 比較函數或函數對象,用于確定元素的優先級。默認為 std::less<T>,它會創建一個大頂堆。
1.1 默認初始化(大頂堆)

最常見的用法,創建一個存儲 int 類型的大頂堆。每次 top() 都會返回最大的元素。

// 默認情況下,是 std::vector 作為容器,std::less 作為比較函數,即大頂堆
std::priority_queue<int> max_heap;max_heap.push(30);
max_heap.push(100);
max_heap.push(25);
max_heap.push(40);// 此刻隊列頂部的元素是 100
std::cout << "Top element is: " << max_heap.top() << std::endl; // 輸出 100
1.2 初始化為小頂堆

如果你想讓 top() 總是返回最小的元素,你需要創建一個小頂堆(Min-Heap)。這需要顯式提供所有模板參數:

  • T: 元素類型。
  • Container: 底層容器,通常是 std::vector<T>
  • Compare: 比較函數,使用 std::greater<T>
// 使用 std::greater<int> 來創建小頂堆
std::priority_queue<int, std::vector<int>, std::greater<int>> min_heap;min_heap.push(30);
min_heap.push(100);
min_heap.push(25);
min_heap.push(40);// 此刻隊列頂部的元素是 25
std::cout << "Top element is: " << min_heap.top() << std::endl; // 輸出 25
1.3 存儲自定義結構體

當存儲自定義類型(如 structclass)時,你需要告訴優先隊列如何比較它們。有兩種主要方法:

方法一:重載 < 運算符(用于大頂堆)

struct Node {int id;int priority;// 重載 < 運算符,priority 越大,優先級越高bool operator<(const Node& other) const {return this->priority < other.priority;}
};std::priority_queue<Node> pq;
pq.push({1, 10});
pq.push({2, 5});
pq.push({3, 20});// top() 將返回 priority 最大的 Node,即 {3, 20}
std::cout << "Top node: id=" << pq.top().id << ", priority=" << pq.top().priority << std::endl;

方法二:提供自定義比較器(更靈活)

如果你不想或不能修改結構體定義,或者需要多種排序方式,可以提供一個自定義的比較函數對象(Functor)。

struct Node {int id;int priority;
};// 自定義比較器結構體
struct CompareNode {// 返回 true 表示 a 的優先級低于 bbool operator()(const Node& a, const Node& b) {// 創建小頂堆,priority 越小,優先級越高return a.priority > b.priority;}
};std::priority_queue<Node, std::vector<Node>, CompareNode> pq;
pq.push({1, 10});
pq.push({2, 5});
pq.push({3, 20});// top() 將返回 priority 最小的 Node,即 {2, 5}
std::cout << "Top node: id=" << pq.top().id << ", priority=" << pq.top().priority << std::endl;

使用 Lambda 表達式(C++11及以上)也可以實現,但定義比較器時需要 decltype

1.4 從已有容器初始化

你可以用一個已有的容器(如 vector)中的元素來初始化優先隊列。

std::vector<int> data = {30, 100, 25, 40};// 從 data 初始化一個大頂堆
std::priority_queue<int> max_heap_from_vec(data.begin(), data.end());std::cout << "Top element from vector init: " << max_heap_from_vec.top() << std::endl; // 輸出 100// 初始化小頂堆
std::priority_queue<int, std::vector<int>, std::greater<int>> min_heap_from_vec(data.begin(), data.end());
std::cout << "Top element from vector init (min-heap): " << min_heap_from_vec.top() << std::endl; // 輸出 25

2. priority_queue 的常用操作

優先隊列的操作非常簡單直觀:

  • push(element): 向隊列中插入一個元素。時間復雜度 O(log n)。
  • pop(): 移除隊首(優先級最高)的元素。時間復雜度 O(log n)。
  • top(): 返回隊首(優先級最高)元素的常引用,不刪除元素。時間復雜度 O(1)。
  • empty(): 檢查隊列是否為空。
  • size(): 返回隊列中元素的數量。

示例代碼:

std::priority_queue<int> pq;std::cout << "Is queue empty? " << (pq.empty() ? "Yes" : "No") << std::endl;pq.push(10);
pq.push(50);
pq.push(20);std::cout << "Queue size: " << pq.size() << std::endl;
std::cout << "Top element: " << pq.top() << std::endl; // 50pq.pop(); // 移除了 50std::cout << "Top element after pop: " << pq.top() << std::endl; // 20// 遍歷并清空優先隊列
std::cout << "Queue elements in priority order: ";
while (!pq.empty()) {std::cout << pq.top() << " ";pq.pop();
}
std::cout << std::endl;
// 輸出: Queue elements in priority order: 20 10

注意priority_queue 沒有提供迭代器,不能像 vector 那樣直接遍歷。唯一的訪問方式就是通過 top() 獲取隊首元素。


3. priority_queue 的應用場景

優先隊列在算法和系統設計中非常有用,尤其適合處理那些需要動態維護“最大/最小”元素的問題。

3.1 Top-K 問題

這是最經典的應用。例如,從一個巨大的數據流中找出最大的 K 個元素。

思路

  • 維護一個大小為 K 的小頂堆
  • 遍歷數據流,對于每個新元素:
    • 如果堆的大小小于 K,直接將元素插入堆中。
    • 如果堆的大小等于 K,將新元素與堆頂元素(當前 K 個元素中最小的那個)比較。
    • 如果新元素大于堆頂元素,則彈出堆頂,并將新元素插入。
  • 遍歷結束后,堆中剩下的 K 個元素就是最大的 K 個元素。

為什么用小頂堆? 因為小頂堆的堆頂是“門檻”,只有比這個門檻大的元素才有資格進入這個“Top-K 圈子”,這樣可以高效地淘汰掉不夠大的元素。

3.2 堆排序(Heap Sort)

雖然 C++ 提供了 std::sort,但優先隊列可以很自然地實現堆排序。

  1. 將所有元素插入一個大頂堆。
  2. 依次從堆中取出堆頂元素,放入結果數組中。取出的順序就是從大到小。
3.3 Dijkstra 算法

在圖論中,Dijkstra 算法用于尋找圖中單源最短路徑。算法的核心是每次都從“待處理”的頂點中,選擇一個距離源點最近的頂點進行擴展。優先隊列(小頂堆)可以完美地勝任這個任務。

  • 優先隊列中存儲 pair<int, int>,即 {距離, 頂點編號}
  • 每次從隊列中取出 top(),就是當前距離源點最近的未訪問頂點。
3.4 Huffman 編碼

在數據壓縮中,Huffman 編碼算法使用優先隊列來構建最優二叉樹(Huffman 樹)。

  • 將每個字符及其頻率作為一個節點放入一個優先隊列(小頂堆)中,頻率越小,優先級越高。
  • 每次從隊列中取出兩個頻率最小的節點,合并成一個新的父節點(頻率為兩者之和),再將新節點放回優先隊列。
  • 重復此過程,直到隊列中只剩一個節點,即 Huffman 樹的根。
3.5 任務調度系統

在操作系統或中間件中,任務調度器需要從多個待執行的任務中選擇一個優先級最高的來執行。優先隊列可以用來管理這些任務,top() 總是返回當前最緊急的任務。


希望這份詳細的說明對你有幫助!

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

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

相關文章

零基礎入門物聯網-遠程門禁開關:硬件介紹

一、成品展示 遠程門禁最終效果 二、項目介紹 整個項目主要是實際使用案例為主&#xff0c;根據自己日常生活中用到物聯網作品為原型&#xff0c;通過項目實例快速理解。項目分為兩部分&#xff1a;制作體驗和深入學習。 制作體驗部分 會提供所有項目資料及制作說明文檔&a…

軟件系統國產化改造開發層面,達夢(DM)數據庫改造問題記錄

本系統前&#xff08;vue&#xff09;后端(java spring boot)為列子&#xff0c;數據庫由MySQL--->DM&#xff08;達夢&#xff09;&#xff0c;中間件為中創的國產化相關軟件&#xff0c;如tomcat、nginx、redis等。重點講數據庫及代碼端的更改&#xff0c;中間件在服務端以…

N8N與Dify:自動化與AI的完美搭配

“N8N”和“Dify”這兩個工具徹底理清楚&#xff0c;它們其實是兩個定位完全不同的開源平臺&#xff0c;各自擅長解決不同類型的問題&#xff0c;但也能協同工作。以下是詳細說明&#xff1a;1. n8n&#xff1a;工作流自動化平臺定位&#xff1a;n8n 是一個專注于跨系統連接與任…

ARM匯編編程(AArch64架構)課程 - 第5章函數調用規范

目錄AAPCS64調用約定參數傳遞規則返回值規則棧幀管理SP寄存器FP寄存器 (X29)棧幀布局示例AAPCS64調用約定 ARM Architecture Procedure Call Standard for 64-bit (AAPCS64) 參數傳遞規則 參數位置寄存器分配特殊規則參數1-8X0-X7 (64-bit) / W0-W7 (32-bit)浮點數使用 V0-V7參…

軟考(軟件設計師)軟件工程-成本評估模型,軟件能力成熟度,軟件配置管理

成本評估模型 Putnam 下面通過一個具體案例&#xff0c;逐步說明Putnam模型的計算過程。我們將開發一個銀行核心交易系統&#xff0c;規模為80萬行代碼&#xff08;LOC&#xff09;&#xff0c;要求24個月內交付。參數符號值說明軟件規模L800,000 LOC通過功能點轉換獲得開發時間…

SASSNet復現

復現結果–Dice&#xff1a;89.354614&#xff0c;Jaccard&#xff1a;80.968917&#xff0c;95HD&#xff1a;7.3987764&#xff0c;誤差在接受范圍 MethodDiceJaccardJaccard # 感想 第19篇完全復現的論文

大數據學習5:網站訪問日志分析

1.數據處理1.1 環境準備進入cd /opt/server/hadoop-3.1.0/sbin文件夾&#xff0c;停止hdfs服務cd /opt/server/hadoop-3.1.0/sbin ./stop-dfs.sh進入/opt/server/hadoop-3.1.0/etc/hadoop文件夾&#xff0c;編輯yarn-site.xml文件/opt/server/hadoop-3.1.0/etc/hadoop vim yarn…

力扣1310. 子數組異或查詢

這一題很明顯的就是用前綴和異或來解決&#xff0c;只要清楚異或的性質&#xff0c;這一題就十分容易。 對異或的性質的講解如下&#xff1a; 異或運算解析 具體代碼如下&#xff1a; class Solution { public:int sum[30005]; vector<int> xorQueries(vector<int>…

React Native 狀態管理方案全面對比

React Native 狀態管理方案全面對比 在 React Native 開發中&#xff0c;狀態管理是構建復雜應用的核心問題。以下是主流狀態管理方案的深度對比分析&#xff1a; 一、基礎方案&#xff1a;useState/useReducer 適用場景 簡單的組件級狀態中等復雜度的局部狀態管理不需要跨組件…

基于Python的程序員數據分析與可視化系統的設計與實現

文章目錄有需要本項目的代碼或文檔以及全部資源&#xff0c;或者部署調試可以私信博主項目介紹背景意義項目展示總結每文一語有需要本項目的代碼或文檔以及全部資源&#xff0c;或者部署調試可以私信博主 項目介紹 互聯網技術飛速發展&#xff0c;數據分析與可視化在程序員工…

Java 枚舉詳解:從基礎到實戰,掌握類型安全與優雅設計

作為一名Java開發工程師&#xff0c;在日常開發中你一定經常使用枚舉&#xff08;enum&#xff09;。自Java 5引入以來&#xff0c;枚舉已經成為定義固定集合常量的首選方式&#xff0c;它比傳統的 public static final 常量更加類型安全、可讀性強&#xff0c;并且具備面向對象…

海外盲盒系統:技術如何重構“信任經濟”?

盲盒的“非透明性”易引發信任危機&#xff0c;而海外盲盒系統通過技術手段構建了“可感知的公平”&#xff1a;1. 區塊鏈存證&#xff1a;概率透明化 隱藏款概率、抽盒記錄上鏈存證&#xff0c;用戶可隨時查詢歷史數據。某歐美用戶通過區塊鏈瀏覽器驗證&#xff0c;確認系統隱…

PyTorch Tensor 操作入門:轉換、運算、維度變換

目錄 1. Tensor 與 NumPy 數組的轉換 1.1 Tensor 轉換為 NumPy 數組 1.2 NumPy 數組轉換為 Tensor 1.3 獲取單個元素的值 2. Tensor 的基本運算 2.1 生成新 Tensor 的運算 2.2 覆蓋原 Tensor 的運算 2.3 阿達瑪積&#xff08;逐元素乘法&#xff09; 2.4 矩陣乘法 3.…

CompletableFuture使用詳解(Super Detailed)

一、 CompletableFuture介紹 多線程開發一般使用Runnable&#xff0c;Callable&#xff0c;Thread&#xff0c;FutureTask&#xff0c;ThreadPoolExecutor&#xff0c;但也有不近如意的地方 Thread Runnable&#xff1a;執行異步任務&#xff0c;沒有返回結果。 Thread Calla…

開源 Arkts 鴻蒙應用 開發(六)數據持久--文件和首選項存儲

文章的目的為了記錄使用Arkts 進行Harmony app 開發學習的經歷。本職為嵌入式軟件開發&#xff0c;公司安排開發app&#xff0c;臨時學習&#xff0c;完成app的開發。開發流程和要點有些記憶模糊&#xff0c;趕緊記錄&#xff0c;防止忘記。 相關鏈接&#xff1a; 開源 Arkts …

【Bluedroid】藍牙協議棧控制器能力解析與核心功能配置機制(decode_controller_support)

本文圍繞Bluedroid藍牙協議棧中控制器能力解析與核心功能配置的關鍵代碼展開&#xff0c;詳細闡述藍牙協議棧如何通過解析控制器硬件能力&#xff0c;構建 SCO/eSCO、ACL 數據包類型支持掩碼&#xff0c;配置鏈路策略、安全服務、查詢與掃描模式等核心功能。這些機制確保協議棧…

小架構step系列07:查找日志配置文件

1 概述 日志這里采用logback&#xff0c;其為springboot默認的日志工具。其整體已經被springboot封裝得比較好了&#xff0c;扔個配置文件到classpath里就能夠使用。 但在實際使用中&#xff0c;日志配置文件有可能需要進行改動&#xff0c;比如日志的打印級別&#xff0c;平…

一文講清楚React Hooks

文章目錄一文講清楚React Hooks一、什么是 React Hooks&#xff1f;二、常用基礎 Hooks2.1 useState&#xff1a;狀態管理基本用法特點2.2 useEffect&#xff1a;副作用處理基本用法依賴數組說明2.3 useContext&#xff1a;上下文共享基本用法特點三、其他常用 Hooks3.1 useRed…

Apache http 強制 https

1. 修改一下文件配置 sudo nano /etc/apache2/sites-enabled/000-default.conf<VirtualHost *:80>ServerName hongweizhu.comServerAlias www.hongweizhu.comServerAdmin webmasterlocalhostDocumentRoot /var/www/html# 強制重定向到HTTPSRewriteEngine OnRewriteCond …

【讀代碼】GLM-4.1V-Thinking:開源多模態推理模型的創新實踐

一、基本介紹 1.1 項目背景 GLM-4.1V-Thinking是清華大學KEG實驗室推出的新一代開源視覺語言模型,基于GLM-4-9B-0414基礎模型構建。該項目通過引入"思維范式"和強化學習課程采樣(RLCS)技術,顯著提升了模型在復雜任務中的推理能力。其創新點包括: 64k超長上下文…