數據結構——堆

數據結構——堆

    • 堆簡介
    • 堆的分類
  • 二叉堆
    • 過程
      • 插入操作
    • 刪除操作
      • 向下調整:
    • 增加某個點的權值
    • 實現
    • 參考代碼:
    • 建堆
      • 方法一:使用 decreasekey(即,向上調整)
      • 方法二:使用向下調整
  • 應用
    • 對頂堆
  • 其他:
    • 配對堆:
    • 左偏樹:

堆簡介

堆是一棵樹,其每個節點都有一個鍵值,且每個節點的鍵值都大于等于/小于等于其父親的鍵值。

每個節點的鍵值都大于等于其父親鍵值的堆叫做小根堆,否則叫做大根堆。STL 中的 priority_queue 其實就是一個大根堆。

(小根)堆主要支持的操作有:插入一個數、查詢最小值、刪除最小值、合并兩個堆、減小一個元素的值。

一些功能強大的堆(可并堆)還能(高效地)支持 merge 等操作。

一些功能更強大的堆還支持可持久化,也就是對任意歷史版本進行查詢或者操作,產生新的版本。

堆的分類

在這里插入圖片描述
習慣上,不加限定提到「堆」時往往都指二叉堆。

二叉堆

結構
從二叉堆的結構說起,它是一棵二叉樹,并且是完全二叉樹,每個結點中存有一個元素(或者說,有個權值)。

堆性質:父親的權值不小于兒子的權值(大根堆)。同樣的,我們可以定義小根堆。本文以大根堆為例。

由堆性質,樹根存的是最大值(getmax 操作就解決了)。

過程

插入操作

插入操作是指向二叉堆中插入一個元素,要保證插入后也是一棵完全二叉樹。

最簡單的方法就是,最下一層最右邊的葉子之后插入。

如果最下一層已滿,就新增一層。

插入之后可能會不滿足堆性質?

向上調整:如果這個結點的權值大于它父親的權值,就交換,重復此過程直到不滿足或者到根。

可以證明,插入之后向上調整后,沒有其他結點會不滿足堆性質。

向上調整的時間復雜度是 O ( l o g n ) O(log n) O(logn)的。

刪除操作

刪除操作指刪除堆中最大的元素,即刪除根結點。

但是如果直接刪除,則變成了兩個堆,難以處理。

所以不妨考慮插入操作的逆過程,設法將根結點移到最后一個結點,然后直接刪掉。

然而實際上不好做,我們通常采用的方法是,把根結點和最后一個結點直接交換。

于是直接刪掉(在最后一個結點處的)根結點,但是新的根結點可能不滿足堆性質……

向下調整:

在該結點的兒子中,找一個最大的,與該結點交換,重復此過程直到底層。

可以證明,刪除并向下調整后,沒有其他結點不滿足堆性質。

時間復雜度 O ( l o g n ) O(log n) O(logn)

增加某個點的權值

很顯然,直接修改后,向上調整一次即可,時間復雜度為 O ( l o g n ) O(log n) O(logn)

實現

我們發現,上面介紹的幾種操作主要依賴于兩個核心:向上調整和向下調整。

考慮使用一個序列 h h h 來表示堆。 h i h_i hi? 的兩個兒子分別是 h 2 h_2 h2? i _i i? h 2 h_2 h2? i _i i? + _+ +? 1 _1 1? 1 1 1 是根結點:

在這里插入圖片描述

參考代碼:

void up(int x) {while (x > 1 && h[x] > h[x / 2]) {swap(h[x], h[x / 2]);x /= 2;}
}void down(int x) {while (x * 2 <= n) {t = x * 2;if (t + 1 <= n && h[t + 1] > h[t]) t++;if (h[t] <= h[x]) break;std::swap(h[x], h[t]);x = t;}
}

建堆

考慮這么一個問題,從一個空的堆開始,插入 n 個元素,不在乎順序。

直接一個一個插入需要 O ( n l o g n ) O(n log n) O(nlogn) 的時間,有沒有更好的方法?

方法一:使用 decreasekey(即,向上調整)

從根開始,按 BFS 序進行。

void build_heap_1() {for (i = 1; i <= n; i++) up(i);
}

為啥這么做:對于第 k 層的結點,向上調整的復雜度為 O ( k ) O(k) O(k) 而不是 O ( l o g n ) O(log n) O(logn)

總復雜度: l o g 1 log 1 log1 + l o g 2 log 2 log2 + … + l o g n log n logn = O ( n l o g n ) O(n log n) O(nlogn)

(在「基于比較的排序」中證明過)

方法二:使用向下調整

這時換一種思路,從葉子開始,逐個向下調整

void build_heap_2() {for (i = n; i >= 1; i--) down(i);
}

換一種理解方法,每次「合并」兩個已經調整好的堆,這說明了正確性。

注意到向下調整的復雜度,為 O ( l o g n ? k ) O(log n - k) O(logn?k),另外注意到葉節點無需調整,因此可從序列約 n/2 的位置開始調整,可減少部分常數但不影響復雜度。

之所以能 O ( n ) O(n) O(n) 建堆,是因為堆性質很弱,二叉堆并不是唯一的。
要是像排序那樣的強條件就難說了。

應用

對頂堆

這個問題可以被進一步抽象成:動態維護一個序列上第 k k k 大的數, k k k 值可能會發生變化。

對于此類問題,我們可以使用對頂堆這一技巧予以解決(可以避免寫權值線段樹或 B S T BST BST帶來的繁瑣)。

對頂堆由一個大根堆與一個小根堆組成,小根堆維護大值即前 k k k 大的值(包含第 k k k 個),大根堆維護小值即比第 k k k 大數小的其他數。

這兩個堆構成的數據結構支持以下操作:

1.維護:當小根堆的大小小于 k k k 時,不斷將大根堆堆頂元素取出并插入小根堆,直到小根堆的大小等于 k k k;當小根堆的大小大于 k k k 時,不斷將小根堆堆頂元素取出并插入大根堆,直到小根堆的大小等于 k k k

2.插入元素:若插入的元素大于等于小根堆堆頂元素,則將其插入小根堆,否則將其插入大根堆,然后維護對頂堆;

3.查詢第 k 大元素:小根堆堆頂元素即為所求;

4.刪除第 k 大元素:刪除小根堆堆頂元素,然后維護對頂堆;

顯然,查詢第 k k k 大元素的時間復雜度是 O ( 1 ) O(1) O(1) 的。由于插入、刪除或調整 k k k 值后,小根堆的大小與期望的 k k k 值最多相差 1 1 1,故每次維護最多只需對大根堆與小根堆中的元素進行一次調整,因此,這些操作的時間復雜度都是 O ( l o g n ) O(log n) O(logn) 的。

其他:

配對堆:

詳見:鏈接: 數據結構——配對堆

左偏樹:

詳見后文。

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

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

相關文章

Python Flask+Echarts+sklearn+MySQL(評論情感分析、用戶推薦、BI報表)項目分享

Python FlaskEchartssklearnMySQL(評論情感分析、用戶推薦、BI報表)項目分享 項目背景&#xff1a; 隨著互聯網的快速發展和智能手機的普及&#xff0c;人們越來越傾向于在網上查找餐廳、購物中心、酒店和旅游景點等商戶的點評和評分信息&#xff0c;以便做出更好的消費決策。…

YOLOv8 : 網絡結構

一. YOLOv8網絡結構 1. Backbone YOLOv8的Backbone同樣參考了CSPDarkNet-53網絡&#xff0c;我們可以稱之為CSPDarkNet結構吧&#xff0c;與YOLOv5不同的是&#xff0c;YOLOv8使用C2f(CSPLayer_2Conv)代替了C3模塊(如果你比較熟悉YOLOv5的網絡結構&#xff0c;那YOLOv8的網絡…

【GitHub】Pycharm本地項目打包上傳到Github倉庫的操作步驟

文章目錄 1、Pycharm端的設置操作2、Github端的設置操作3、Pycharm上配置Github4、Git本地項目至GitHub倉庫5、前往Github中查看確認6、常見報錯 1、Pycharm端的設置操作 通過CtrlAltS快捷組合鍵的方式&#xff0c;打開設置&#xff0c;導航到版本控制一欄中的Git&#xff0c;…

Gin安裝解決國內go 與 熱加載

get 方式安裝超時問題&#xff0c;國內直接用官網推薦的下面這個命令大概率是安裝不成功的 go get -u github.com/gin-gonic/gin 可以在你的項目目錄下執行下面幾個命令&#xff1a; 比如我的項目在E:\Oproject\zl cmd E:\Oproject\zl>就在目錄下執行 go env -w GO111…

回歸預測 | MATLAB實現GRU門控循環單元多輸入多輸出

回歸預測 | MATLAB實現GRU門控循環單元多輸入多輸出 目錄 回歸預測 | MATLAB實現GRU門控循環單元多輸入多輸出預測效果基本介紹程序設計往期精彩參考資料 預測效果 基本介紹 MATLAB實現GRU門控循環單元多輸入多輸出&#xff0c;數據為多輸入多輸出預測數據&#xff0c;輸入10個…

pytorch安裝VAE項目詳解

安裝VAE項目 一、 基本環境二、代碼來源三、搭建conda環境四、下載數據集五、啟動項目六、其他相關問題 一、 基本環境 工具版本號OSwin 11pycharm2020.1GPU3050 二、代碼來源 github地址為&#xff1a; https://github.com/AntixK/PyTorch-VAE/blob/8700d245a9735640dda458d…

ZooKeeper的應用場景(集群管理、Master選舉)

5 集群管理 隨著分布式系統規模的日益擴大&#xff0c;集群中的機器規模也隨之變大&#xff0c;因此&#xff0c;如何更好地進行集群管理也顯得越來越重要了。 所謂集群管理&#xff0c;包括集群監控與集群控制兩大塊&#xff0c;前者側重對集群運行時狀態的收集&#xff0c;后…

08 - 追加commit和修改最新的commit message

查看所有文章鏈接&#xff1a;&#xff08;更新中&#xff09;GIT常用場景- 目錄 文章目錄 1. 追加提交2. 修改最新的commit message 1. 追加提交 將改動追加到上一次的commit 現在我已經修改了Readme文件并且已經add、commit操作&#xff0c;但是還沒有push到遠程倉庫&#x…

【左神算法刷題班】第17節:在有序二維數組中查找目標值、等于目標字符串的子序列個數

第17節 題目1&#xff1a;在有序二維數組中查找目標值 給定一個每一行有序、每一列也有序&#xff0c;整體可能無序的二維數組 再給定一個數num&#xff0c; 返回二維數組中有沒有num這個數 例子 數組如下&#xff0c;找 6 是否存在。 1 3 5 7 2 4 6 13 3 9 14 …

“心理健康人工智能產學研創新聯盟”揭牌成立|深蘭科技

8月14日上午&#xff0c;“2023樹洞救援年會”在上海舉行&#xff0c;會上舉行了“心理健康人工智能產學研創新聯盟”的簽約和揭牌儀式。“樹洞行動救援團”創始人深蘭科技科學院智能科學首席科學家、荷蘭阿姆斯特丹自由大學人工智能系終身教授黃智生&#xff0c;深蘭科技集團創…

華納云:ubuntu啟動寶塔的方法是什么

要在Ubuntu上啟動寶塔面板&#xff08;BT Panel&#xff09;&#xff0c;請按照以下步驟操作&#xff1a; 下載并安裝寶塔面板&#xff1a; 在終端中執行以下命令&#xff0c;以下載并運行寶塔面板的安裝腳本&#xff1a; sudo su wget -O install.sh http://download.bt.c…

Git 常用操作

一、Git 常用操作 1、Git 切換分支 git checkout命令可以用于三種不同的實體&#xff1a;文件&#xff0c;commit&#xff0c;以及分支。checkout的意思就是對于一種實體的不同版本之間進行切換的操作。checkout一個分支&#xff0c;會更新當前的工作空間中的文件&#xff0c;…

68 # 中間層如何請求其他服務

前端 ajax 有跨域問題&#xff0c;可以先訪問中間層&#xff0c;在通過 node 去請求別的服務端口&#xff0c;可以解決跨域問題 編寫中間層調用 // 中間層的方式const http require("http");// http.get 默認發送 get 請求 // http.request 支持其他請求格式 postl…

Java基礎知識實際應用(學生信息管理系統、猜拳小游戲、打印日歷)

一、Java學生信息管理系統 這個系統包含了添加、修改、刪除、查詢和顯示所有學生信息等功能。您可以在此基礎上進行修改和完善&#xff0c;以適應您的需求。 import java.util.Scanner;public class StudentManagementSystem {private static Scanner scanner new Scanner(S…

haproxy負載均衡

1、配置環境 作用環境windows測試  192.168.33.158 172.25.0.11 haproxy負載均衡haproxy&#xff1a;2.8.1&#xff0c;centos7172.25.0.31web服務器1--rs1Apache&#xff1a;2.4&#xff0c;redhat9172.25.0.32web服務器2--rs2Apache&#xff1a;2.4 &#xff0c; redhat9 2、…

Azure使用CLI創建VM

使用CLI創建VM之前&#xff0c;確保資源中的IP資源已經釋放掉了&#xff0c;避免創建的過程中沒有可以利用的公共IP地址打開 cloudshell ,并輸入創建CLI的命令如下&#xff0c;-n指定名稱&#xff0c;-g指定資源組&#xff0c;image指定鏡像&#xff0c;admin-usernam指定用戶名…

【滴滴提前批】移掉 K 位數字

題目 給你一個以字符串表示的非負整數 num 和一個整數 k &#xff0c;移除這個數中的 k 位數字&#xff0c;使得剩下的數字最小。請你以字符串形式返回這個最小的數字。 示例 1 &#xff1a; 輸入&#xff1a;num "1432219", k 3 輸出&#xff1a;"1219&quo…

Maven進階1 -- 分模塊開發、依賴管理、聚合與繼承、屬性、版本管理、多環境開發、跳過測試

目錄 1.分模塊開發 將原始模塊按照功能拆分成若干個子模塊&#xff0c;方便模塊間的相互調用&#xff0c;接口共享。 案例&#xff1a;拆分一下這個SSM整合案例 ①創建maven模塊 demo項目下的pom.xml文件&#xff08;主要看一下依賴&#xff09; <dependencies><!…

【wiki】電競助手掉落提醒 EsportsHelper「Webhook」「釘釘」「飯碗警告」「企業微信」「Discord」

介紹 本項目鏈接 Github電競助手鏈接 github上項目電競助手(EsportsHelper)的掉落提醒配置教程,當有掉寶的時候會發送你信息提示. 至于這個腳本是怎么使用的簡單說一下,就是通過自動觀看英雄聯盟直播 從而獲取獎勵(僅限直營服),有興趣的可以去github上看readme,非常詳細,支持…

stable-diffusion-webui啟動No Python at ‘C:\xxx\xxx\python.exe‘

打開webui.bat 把 if not defined VENV_DIR (set "VENV_DIR%~dp0%venv") 中的%~dp0venv改成自己python的安裝路徑就行獲取直接set值即可 如 set VENV_DIRD:\Users\xxx\AppData\Local\Programs\Python\Python310 另外就是直接運行webui-user.bat也可以 如果運行…