堆(Heap)

1. 堆(Heap)

1.1. Python實現堆的插入、堆頂刪除和排序

class MaxHeap:def __init__(self):# 初始化空堆,使用列表表示self.heap = []def insert(self, val):# 插入元素并執行上浮self.heap.append(val)self._sift_up(len(self.heap) - 1)def delete(self):# 刪除并返回堆頂元素if not self.heap:return Noneself._swap(0, len(self.heap) - 1)max_val = self.heap.pop()self._sift_down(0)return max_valdef build_heap(self, arr):# 從任意數組構建大頂堆self.heap = arr[:]for i in range((len(self.heap) - 2) // 2, -1, -1):self._sift_down(i)def heapsort(self):# 原地堆排序(不會額外開辟空間)n = len(self.heap)# 先構建堆for i in range((n - 2) // 2, -1, -1):self._sift_down(i)# 每次把最大值(堆頂)放到末尾,然后縮小堆范圍for end in range(n - 1, 0, -1):self._swap(0, end)self._sift_down(0, end)def _sift_up(self, idx):# 上浮操作,保持堆結構parent = (idx - 1) // 2while idx > 0 and self.heap[idx] > self.heap[parent]:self._swap(idx, parent)idx = parentparent = (idx - 1) // 2def _sift_down(self, idx, size=None):# 下沉操作,保持堆結構(可傳入范圍用于排序)if size is None:size = len(self.heap)while True:largest = idxleft = 2 * idx + 1right = 2 * idx + 2if left < size and self.heap[left] > self.heap[largest]:largest = leftif right < size and self.heap[right] > self.heap[largest]:largest = rightif largest == idx:breakself._swap(idx, largest)idx = largestdef _swap(self, i, j):# 輔助函數:交換堆中兩個元素self.heap[i], self.heap[j] = self.heap[j], self.heap[i]def __str__(self):# 返回堆內容的字符串表示return str(self.heap)
import heapqdef heapsort_asc(iterable):heap = []for value in iterable:heapq.heappush(heap, value)  # 構建最小堆return [heapq.heappop(heap) for _ in range(len(heap))]  # 升序彈出# 示例
nums = [7, 2, 5, 3, 1]
print("升序堆排序結果:", heapsort_asc(nums))

1.2. 堆的定義

1. 堆的基本概念

  • 是一種特殊的樹形數據結構,廣泛應用于算法中,如堆排序。
  • 堆的兩個主要特征
  1. 完全二叉樹:除了最后一層,其他層的節點都已滿,最后一層的節點靠左排列。
  2. 節點值的大小關系

????????大頂堆(Max-Heap):每個節點的值都大于或等于其子節點的值。

????????小頂堆(Min-Heap):每個節點的值都小于或等于其子節點的值。

2. 堆的實現與存儲

  • 堆通常使用數組來存儲,因為完全二叉樹的結構適合用數組表示。
  • 對于列表下標為 i 的節點:

左子節點下標:2i + 1

右子節點下標:2i + 2

父節點下標:i -1 // 2

1.3. 堆的核心操作

完全二叉樹比較適合用數組來存儲。用數組來存儲完全二叉樹是非常節省存儲空間的。因為我們不需要存儲左右子節點的指針,單純地通過數組的下標,就可以找到一個節點的左右子節點和父節點。

具體python代碼見5.1,以大頂堆為例。

1. 往堆中插入一個元素

  • 將新元素插入堆的最后,然后進行堆化(Heapify)操作來恢復堆的性質。
  • 堆化分為兩種方式:

自下而上堆化:從插入的節點開始,依次與父節點比較,直到堆的性質恢復。

2. 刪除堆頂元素

刪除堆頂元素(最大或最小)后,將最后一個元素移動到堆頂,并進行自上而下堆化來恢復堆的性質。

時間復雜度:

一個包含 n個節點的完全二叉樹,樹的高度不會超過 log2n。堆化的過程是順著節點所在路徑比較交換的,所以堆化的時間復雜度跟樹的高度成正比,也就是 O(logn)。插入數據和刪除堆頂元素的主要邏輯就是堆化,所以,往堆中插入一個元素和刪除堆頂元素的時間復雜度都是 O(logn)

3. 堆排序

堆排序的過程大致分解成兩個大的步驟,建堆排序

建堆:

  • 將數組構建成一個堆。
  • 可以從前往后逐個插入元素構建堆(自下而上堆化)。
  • 或者從后往前處理,使用自上而下堆化的方式來構建堆。

排序:

每次將堆頂元素(最大或最小)與最后一個元素交換,將堆的大小減小 1,然后進行堆化。重復此過程直到數組排序完成。

不是穩定的排序算法。

時間復雜度分析:

建堆:

雖然每個節點堆化的時間復雜度為 O(log n),但由于堆的層數遞減,因此建堆的時間復雜度是 O(n)

排序:

每次刪除堆頂元素并堆化的時間復雜度為 O(log n),重復此過程 n 次,因此堆排序的總時間復雜度是 O(n log n)

快速排序 vs 堆排序:性能對比表(實際開發視角)

對比維度

快速排序(Quick Sort)

堆排序(Heap Sort)

數據訪問模式

局部順序訪問:訪問相鄰元素,緩存友好

非順序訪問:跳躍式訪問(如下標 1 → 2 → 4 → 8),緩存不友好

緩存命中率

高(連續訪問內存,有利于 CPU 緩存預取)

低(訪問分散,頻繁觸發緩存未命中)

數據交換次數

相對較少,尤其在數據部分有序的情況下

多:建堆過程中頻繁打亂已有順序,導致額外的交換

對初始有序性敏感

是(部分有序時性能更好

否(建堆打亂順序

排序過程破壞有序度

否,盡量保持已有的順序結構

是,建堆導致已有順序被打亂

1.4. 堆的應用

1. 優先級隊列(Priority Queue)

定義:

  • 與普通隊列不同,出隊順序按優先級高低而非 FIFO。
  • 堆可高效實現優先級隊列:

????????????????插入元素:O(logn)

????????????????取出優先級最高元素(堆頂):O(logn)

應用示例:

合并有序小文件:

  • 場景:將 100 個 100MB 的有序小文件合并為一個大文件。
  • 方案:

????????每個文件取一個字符串放入小頂堆。

????????每次從堆頂取最小值寫入結果文件,再從對應文件中取下一個值加入堆。

????????時間復雜度大幅優于線性遍歷(數組)。

高性能定時器:

  • 維護很多任務,每個任務有執行時間。
  • 傳統方法每秒輪詢掃描任務表,低效。
  • 使用小頂堆優化:

????????????????堆頂存放最早執行的任務

????????????????定時器睡眠到該任務執行時間,節省資源。

????????????????每次取堆頂更新下一次喚醒時間。

2. 利用堆求 Top K 問題

Top K 分為兩類:

靜態 Top K(一次性獲取):

  • 使用K 大小的小頂堆
  • 遍歷整個數組:

????????? ? ?若當前元素 > 堆頂:替換堆頂,重新堆化。

  • 時間復雜度:O(nlogK)

動態 Top K(實時查詢):

  • 維護一個固定大小為 K 的小頂堆。
  • 插入新數據時:

????????若新數據 > 堆頂:替換堆頂。

????????否則忽略。

  • 查詢時直接返回堆中元素。

3. 利用堆求中位數(及任意百分位數據)

靜態數據集合:

  • 可直接排序取中位數,代價高但結果固定。

動態數據集合:

  • 方法:雙堆法

????????大頂堆(max-heap):存前半部分數據。

????????小頂堆(min-heap):存后半部分數據,且小頂堆中的數據都大于大頂堆中的數據。

????????保持兩個堆平衡(大小相差不超過1)。

????????中位數取決于兩個堆的堆頂元素。

優勢:

  • 每次插入數據后,只需調整兩個堆即可,效率高。
  • 實現實時獲取中位數,時間復雜度約為 O(logn)

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

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

相關文章

Spring類

BeanDefinition BeanDefinition表示Bean定義&#xff0c;BeanDefinition中存在很多屬性用來描述一個Bean的特點。比如&#xff1a; class&#xff0c;表示Bean類型scope&#xff0c;表示Bean作用域&#xff0c;單例或原型等lazyInit&#xff1a;表示Bean是否是懶加載initMeth…

在vue中this.$emit有哪些作用,事件監控具體含義,以及這些子組件能封裝哪些功能組件

this.$emit 的作用 this.$emit 的作用是觸發一個自定義事件&#xff0c;并將數據傳遞給父組件。父組件可以通過 v-on&#xff08;或 &#xff09;監聽這個事件&#xff0c;并在事件觸發時執行相應的處理函數。 this.content 的作用 this.content 是子組件的 props&#xff0…

前端流行框架Vue3教程:16. 組件事件配合`v-model`使用

組件事件配合v-model使用 如果是用戶輸入&#xff0c;我們希望在獲取數據的同時發送數據配合v-model 來使用&#xff0c;幫助理解組件間的通信和數據綁定。 &#x1f9e9; 第一步&#xff1a;創建子組件&#xff08;SearchComponent.vue&#xff09; 這個組件用于處理用戶的搜…

《Navicat之外的新選擇:實測支持國產數據庫的SQLynx核心功能解析》

數據庫工具生態的新變量 在數據庫管理工具領域&#xff0c;Navicat長期占據開發者心智。但隨著國產數據庫崛起和技術信創需求&#xff0c;開發者對工具的兼容性、輕量化和本土化適配提出了更高要求。近期體驗了一款名為SQLynx的國產數據庫管理工具&#xff08;麥聰旗下產品&am…

AgenticSeek開源的完全本地的 Manus AI。無需 API,享受一個自主代理,它可以思考、瀏覽 Web 和編碼,只需支付電費。

?一、軟件介紹 文末提供程序和源碼下載 AgenticSeek開源的完全本地的 Manus AI。無需 API&#xff0c;享受一個自主代理&#xff0c;它可以思考、瀏覽 Web 和編碼&#xff0c;只需支付電費。這款支持語音的 AI 助手是 Manus AI 的 100% 本地替代品 &#xff0c;可自主瀏覽網頁…

vue3.0的name屬性插件——vite-plugin-vue-setup-extend

安裝 這個由于是在開發環境下的一個插件 幫助我們支持name屬性 所以需要是-D npm i vite-plugin-vue-setup-extend -D在pasckjson中無法注釋每個插件的用處 可以在vscode中下載一個JsonComments這樣可以在json中添加注釋方便日后維護和查閱API 引入 在vite.config.js中 im…

Linux基礎 -- 在內存中使用chroot修復eMMC

Linux基礎 – 在內存中使用chroot修復eMMC 概述 本教程將介紹如何在Linux系統中&#xff0c;使用chroot在內存中構建一個臨時系統&#xff0c;并在不依賴原有系統的情況下修復eMMC&#xff08;如/dev/mmcblk2&#xff09;磁盤。該方法適用于嵌入式系統修復、磁盤清理以及離線…

人工智能、深度學習、機器學習的聯系與區別

定義 人工智能&#xff08;AI - Artificial Intelligence&#xff09; &#xff1a;是研究、開發用于模擬、延伸和擴展人的智能的理論、方法、技術及應用系統的一門新的技術科學。它旨在讓計算機能夠像人類一樣思考、學習和決策&#xff0c;涉及到諸如計算機視覺、自然語言處理…

web第二次課后作業--設計一個注冊登錄系統

一、頁面展示 登錄頁面 提交頁面 二、代碼 2.1 登錄頁面 <% page language"java" contentType"text/html; charsetUTF-8"pageEncoding"UTF-8"%><html> <head><meta http-equiv"Content-Type" content"…

電腦桌面便簽哪個好?2025年電腦免費用的便簽軟件推薦

我們都知道&#xff0c;一個優秀的桌面便簽軟件可以成為提高效率的得力助手。無論是記錄臨時靈感、管理待辦事項&#xff0c;還是提醒重要日程&#xff0c;合適的便簽工具都能讓您的數字生活更加有序。本文將為您介紹2025年最值得推薦的免費電腦桌面便簽軟件&#xff0c;從Wind…

【SPIN】用Promela驗證順序程序:從斷言到SPIN實戰(SPIN學習系列--2)

你寫了一段自認為“天衣無縫”的程序&#xff0c;但如何確保它真的沒有bug&#xff1f;靠手動測試&#xff1f;可能漏掉邊界情況&#xff1b;靠直覺&#xff1f;更不靠譜&#xff01;這時候&#xff0c;Promela SPIN組合就像程序的“顯微鏡”——用形式化驗證技術&#xff0c;…

LabVIEW中樣條插值實現及應用

在 LabVIEW 編程環境下&#xff0c;B - 樣條插值是處理數據擬合與曲線平滑的重要工具。它憑借靈活的特性和良好的數學性質&#xff0c;在眾多工程領域中發揮著關鍵作用&#xff0c;能夠高效地根據離散數據點生成平滑連續的曲線&#xff0c;為數據分析和處理提供了有力支持。 一…

【油藏地球物理正演軟件ColchisFM】基于數據驅動的油藏參數疊前地震反演研究進展

科吉思基于油藏地球物理參數的正演軟件ColchisFM&#xff0c;有機融合了巖石物理正演與地震正演&#xff0c;具有良好的適用性和便捷性&#xff0c;在業內已經廣泛使用。當用戶在做正演模擬的同時&#xff0c;自然會聯想到是否可以直接開展油藏地球物理參數反演呢&#xff1f;答…

互聯網大廠Java求職面試:AI與大模型集成的云原生架構設計

互聯網大廠Java求職面試&#xff1a;AI與大模型集成的云原生架構設計 引言 在現代互聯網企業中&#xff0c;AI與大模型技術的應用已經成為不可或缺的一部分。特別是在短視頻平臺、電商平臺和金融科技等領域&#xff0c;如何高效地將大模型集成到現有的云原生架構中是一個巨大…

Web GIS可視化地圖框架Leaflet、OpenLayers、Mapbox、Cesium、ArcGis for JavaScript

Mapbox、OpenLayers、Leaflet、ArcGIS for JavaScript和Cesium是五種常用的Web GIS地圖框架&#xff0c;它們各有優缺點&#xff0c;適用于不同的場景。還有常見的3d庫和高德地圖、百度地圖。 1. Mapbox 官網Mapbox Gl JS案列&#xff1a;https://docs.mapbox.com/mapbox-gl-…

專項智能練習(加強題型)-DA-02

2. 單選題 近年來&#xff0c;“斜杠青年”成為很多人的時尚追求。它指的是一群不再滿足“專一職業”生活方式&#xff0c;而選擇擁有多重職業和身份的多元生活人群。對此&#xff0c;有人認為&#xff0c;新產業新技術新業態不斷更迭&#xff0c;激烈的競爭促使青年人不斷進行…

使用gitbook 工具編寫接口文檔或博客

步驟一&#xff1a;在項目目錄中初始化一個 GitBook 項目 mkdir mybook && cd mybook git init npm init -y步驟二&#xff1a;添加書籍結構&#xff08;如 book.json, README.md&#xff09; echo "# 我的書" > README.md echo "{}" > bo…

Malformed input or input contains unmappable characters解決

JDK 17 文件上傳編碼異常解決方案技術文檔 1. 問題背景 在 JDK 17 環境下&#xff0c;文件上傳過程中可能拋出 Malformed input or input contains unmappable characters 錯誤。此問題通常由以下原因觸發&#xff1a; 文件路徑/名稱包含非 ASCII 字符&#xff08;如中文、日…

MyBatis 的分頁插件 c

前言 大型項目的數據體量很大&#xff0c;在前端界面展示時為保障展示效果&#xff0c;會要求接口快速返回&#xff0c;這時候后端會選擇分頁獲取數據&#xff0c;只傳遞要查詢的頁碼數據。這就避免了大多問題&#xff0c;達到快速返回的效果。 常用的分頁有2種&#xff1a; …

Linux:理解文件系統

1.理解硬件 1.1磁盤 機械磁盤是計算機中的?個機械設備 磁盤--- 外設 慢 容量?&#xff0c;價格便宜 1.2磁盤物理結構 1.3磁盤的存儲結構 扇區&#xff1a;是磁盤存儲數據的基本單位&#xff0c;512字節&#xff0c;塊設備 如何定位?個扇區呢&#xff1f; 確定磁頭要訪…