#### golang中【堆】的使用及底層 ####

?聲明,本文部分內容摘自:

?Go: 深入理解堆實現及應用-騰訊云開發者社區-騰訊云

數組實現堆 | WXue

堆(Heap)是實現優先隊列的數據結構,Go提供了接口和方法來操作堆。

應用

package mainimport ("container/heap""sort"
)/*
題目:給你一個整數數組 nums,有一個大小為 k 的滑動窗口從數組的最左側移動到數組的最右側。你只可以看到在滑動窗口內的 k 個數字,滑動窗口每次只向右移動一位,返回滑動窗口中的最大值。示例:輸入:nums = [1,3,-1,-3,5,3,6,7], k = 3輸出:[3,3,5,5,6,7]解釋:滑動窗口的位置                最大值---------------------------------[1 3  -1] -3  5  3  6  7       31 [3  -1  -3] 5  3  6  7       31  3 [-1  -3  5] 3  6  7       51  3  -1 [-3  5  3] 6  7       51  3  -1  -3 [5  3  6] 7       61  3  -1  -3  5 [3  6  7]      7
題解:大根堆可以幫助我們實時維護一系列元素中的最大值。初始時,我們將數組 nums 的前 k 個元素放入優先隊列中。每當我們向右移動窗口時,我們就可以把一個新的元素放入優先隊列中,此時堆頂的元素就是堆中所有元素的最大值。然而這個最大值可能并不在滑動窗口中,在這種情況下,這個值在數組 nums 中的位置出現在滑動窗口左邊界的左側。因此,當我們后續繼續向右移動窗口時,這個值就永遠不可能出現在滑動窗口中了,我們可以將其永久地從優先隊列中移除。我們不斷地移除堆頂的元素,直到其確實出現在滑動窗口中。此時,堆頂元素就是滑動窗口中的最大值。為了方便判斷堆頂元素與滑動窗口的位置關系,我們可以在優先隊列中存儲二元組 (num,index),表示元素 num 在數組中的下標為 index。
*/var a []int// heap 實現了標準庫的heap.Interface接口
type hp struct {sort.IntSlice // type IntSlice []int
}func (h hp) Less(i, j int) bool {return a[h.IntSlice[i]] > a[h.IntSlice[j]]
}
func (h *hp) Push(v interface{}) {h.IntSlice = append(h.IntSlice, v.(int))
}
func (h *hp) Pop() interface{} {a := h.IntSlicev := a[len(a)-1]h.IntSlice = a[:len(a)-1]return v
}func maxSlidingWindow(nums []int, k int) (ans []int) {ans = make([]int, 1, len(nums)-k+1)a = nums// 初始化堆(優先隊列)queue := &hp{make([]int, k)} // 優先隊列for i := 0; i < k; i++ {queue.IntSlice[i] = i // 注意堆里存的是數組下標而非數組值,對應Less函數里的比較時需要a[h.IntSlice[i]]來比較值}heap.Init(queue) // 初始化+向下調整// 賦值ans[0],因為不需要判斷IntSlice[0]的元素是不是在邊界外的左側ans[0] = nums[queue.IntSlice[0]] // IntSlice[0] 下標為0=數組IntSlice的頭部=堆頂元素// 窗口滑動for i := k; i < len(nums); i++ {heap.Push(queue, i)            // 入堆+向上調整for queue.IntSlice[0] <= i-k { // 判斷IntSlice[0]的元素是不是在邊界外的左側heap.Pop(queue) // 出堆+向下調整}ans = append(ans, nums[queue.IntSlice[0]]) // IntSlice[0] 下標為0=數組頭部=堆頂元素}return ans
}func main() {res := maxSlidingWindow([]int{1, 3, -1, -3, 5, 3, 6, 7}, 3)println(res)
}

底層

包:container/heap

接口:heap.Interface

源碼:

type Interface interface {sort.InterfacePush(x interface{}) // 添加元素Pop() interface{}   // 彈出元素
}

其中,注意,實現heap.Interface接口需要嵌入sort.Interface,后者包含Len()、Less(i, j int) bool和Swap(i, j int)方法,用于確定元素間的排序。

全部源碼:

type Interface interface {sort.InterfacePush(x any) // add x as element Len()Pop() any   // remove and return element Len() - 1.
}func Init(h Interface) {// heapifyn := h.Len()for i := n/2 - 1; i >= 0; i-- {down(h, i, n)}
}// Push pushes the element x onto the heap.
// The complexity is O(log n) where n = h.Len().
func Push(h Interface, x any) {h.Push(x)up(h, h.Len()-1)
}func Pop(h Interface) any {n := h.Len() - 1h.Swap(0, n)down(h, 0, n)return h.Pop()
}func Remove(h Interface, i int) any {n := h.Len() - 1if n != i {h.Swap(i, n)if !down(h, i, n) {up(h, i)}}return h.Pop()
}func Fix(h Interface, i int) {if !down(h, i, h.Len()) {up(h, i)}
}func up(h Interface, j int) {for {i := (j - 1) / 2 // parentif i == j || !h.Less(j, i) {break}h.Swap(i, j)j = i}
}func down(h Interface, i0, n int) bool {i := i0for {j1 := 2*i + 1if j1 >= n || j1 < 0 { // j1 < 0 after int overflowbreak}j := j1 // left childif j2 := j1 + 1; j2 < n && h.Less(j2, j1) {j = j2 // = 2*i + 2  // right child}if !h.Less(j, i) {break}h.Swap(i, j)i = j}return i > i0
}

其中:

? ? ① 初始化(Init): 對一個未排序的切片構建堆。這是通過down方法實現的,down方法確保元素下沉到正確的位置,維持堆的性質。

? ? ② 添加元素(Push): 元素被添加到切片的末尾,然后通過up方法上浮到正確的位置。

注意:標準庫中的push函數中,第一行調用的【h.Push(x)】是上層業務代碼中自行實現的heap.Interface的堆實例的push方法。

func Push(h Interface, x any) {
?? ?h.Push(x)
?? ?up(h, h.Len()-1)
}

? ? ③ 刪除元素(Pop): 堆頂元素(切片的第一個元素)被移動到切片末尾并返回,然后新的堆頂元素通過down方法恢復堆的性質。

? ? ④ 刪除任意元素(Remove): 類似Pop,但可以移除指定位置的元素。此操作需要綜合up和down方法來調整堆。

? ? ⑤ 修改元素并調整堆(Fix): 如果堆中某個元素被外部修改了(比如優先級改變),Fix方法會根據這個修改后的新值重新調整堆。

堆是一顆完全二叉樹,可由數組表示

完全二叉樹,逐層而下,從左到右,結點的位置完全由其序號覺得,因此可以用數組來實現。

計算各結點下標的公式,其中?𝑟𝑟?表示結點的下標,范圍在 0 ~ n-1 之間,n 是二叉樹結點的總數。

𝑃𝑎𝑟𝑒𝑛𝑡(𝑟)=?(𝑟?1)/2?𝑃𝑎𝑟𝑒𝑛𝑡(𝑟)=?(𝑟?1)/2??向下取整,當?𝑟≠0𝑟≠0?時

𝐿𝑒𝑓𝑡𝑐?𝑖𝑙𝑑(𝑟)=2𝑟+1𝐿𝑒𝑓𝑡𝑐?𝑖𝑙𝑑(𝑟)=2𝑟+1, 當?2𝑟+1<𝑛2𝑟+1<𝑛?時

𝑅𝑖𝑔?𝑡𝑐?𝑖𝑙𝑑(𝑟)=2𝑟+2𝑅𝑖𝑔?𝑡𝑐?𝑖𝑙𝑑(𝑟)=2𝑟+2, 當?2𝑟+2<𝑛2𝑟+2<𝑛?時

𝐿𝑒𝑓𝑡𝑠𝑖𝑏𝑙𝑖𝑛𝑔()=𝑟?1𝐿𝑒𝑓𝑡𝑠𝑖𝑏𝑙𝑖𝑛𝑔()=𝑟?1, 當 r 為偶數時

𝑅𝑖𝑔?𝑡𝑠𝑖𝑏𝑙𝑖𝑛𝑔()=𝑟+1𝑅𝑖𝑔?𝑡𝑠𝑖𝑏𝑙𝑖𝑛𝑔()=𝑟+1?, 當 r 為奇數并且?𝑟+1<𝑛𝑟+1<𝑛?時

20200328Build_heap

插入數值:在堆的末尾插入,然后不斷向上提升,直到沒有大小顛倒。

刪除數值:首先把堆的最后一個節點的數值放到根上去,并且刪除最后一個節點,然后不斷向下交換直到沒有大小顛倒為止。向下交換的時候如果 2 個兒子都比自己小,那么選擇數值較小的兒子進行交換。

復雜度:建堆需要 On?的時間,但刪除、插入都和樹深度成正比,時間復雜度是 O𝑛𝑙𝑜𝑔𝑛。

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

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

相關文章

結構方程模型-驗證性因子分析模型

初級 第7講 驗證性因子分析模_嗶哩嗶哩_bilibili

使用 ESP32 接收來自 MAX4466 模擬麥克風模塊的數據,并通過 DAC 輸出模擬音頻信號,可以通過以下步驟實現:

硬件準備 ESP32 開發板MAX4466 模擬麥克風模塊揚聲器或耳機接線 MAX4466 模塊輸出(AO) -> ESP32 ADC 引腳(如 GPIO 34)ESP32 DAC 引腳(如 GPIO 25 或 GPIO 26) -> 揚聲器或耳機軟件準備 音頻采集DAC 轉碼并播放代碼實現 以下代碼展示了如何從 MAX4466 讀取模擬音頻…

【Go語言入門學習筆記】Part7.閉包和defer關鍵字

一、前言 閉包有點像對象&#xff0c;而defer適合于類似功能中利用資源時&#xff0c;提前寫幾句defer 釋放資源&#xff0c;防止后面釋放資源忘記寫釋放資源。 二、學習代碼 package mainimport ("fmt" )// getC的返回值是一個函數&#xff0c;需要的參數為空&…

GitHub Pull Request流程詳解

GitHub Pull Request流程詳解 在協作開發中&#xff0c;GitHub的Pull Request&#xff08;PR&#xff09;功能至關重要&#xff0c;它允許開發者在代碼庫中進行修改、審查和合并代碼。本文將詳細介紹GitHub Pull Request的完整流程&#xff0c;幫助你更好地理解和使用這一強大…

網絡安全的十字路口:向“架構化”轉移

市場條件正在快速變化 針對上述這些問題&#xff0c;在這段時間里&#xff0c;安全技術供應商推出了許多技術解決方案&#xff0c;比如SIEM、SOAR、XDR、UEBA等&#xff0c;但新產品的推出并未使得安全態勢有所好轉&#xff0c;許多問題依然存在&#xff0c;這導致了市場動態的…

【DevOps】Java內存分配與JVM參數詳解

目錄 引言 JVM內存結構 JVM參數概述 堆內存分配 年輕代與老年代 調整堆內存大小 調整年輕代與老年代比例 元空間分配 調整元空間大小 垃圾回收 調整GC參數 調整GC日志 線程棧分配 調整線程棧大小 性能調優 結論 在Java開發中&#xff0c;理解Java虛擬機&#x…

claude3.5寫作——《基于灰色預測的中國人口數量預測》

文章目錄 站點和提問引言一、灰色預測模型介紹二、中國歷年人口數據三、灰色預測模型的建立1.建立原始序列2.生成1-AGO序列3.計算背景值4.構造數據矩陣并計算參數5.模型檢驗6.模型預測 四、預測結果分析五、政策建議結語參考文獻 站點和提問 站點&#xff1a;中國官方克勞德3.…

如何更改 Python pip 源為國內源

在使用 Python 安裝包工具 pip 時&#xff0c;經常會遇到下載速度慢的問題。這通常是因為默認使用的官方源 https://pypi.org/simple 在國內訪問速度較慢。為了提高下載速度&#xff0c;我們可以將 pip 源更改為國內的鏡像源。本文將介紹如何臨時和永久地更改 pip 源為國內源。…

光伏電站數據采集方案(基于工業路由器部署)

? 一、方案概述 本方案采用星創易聯SR500工業路由器作為核心網關設備&#xff0c;實現對光伏電站現場數據的實時采集、安全傳輸和遠程監控。SR500具備多接口、多功能、高可靠性等特點&#xff0c;能夠滿足光伏電站數據采集的各種需求。&#xff08;key-iot.com/iotlist/sr500…

RK3568平臺(opencv篇)ubuntu18.04上安裝opencv環境

一.什么是 OpenCV-Python OpenCV-Python 是一個 Python 綁定庫&#xff0c;旨在解決計算機視覺問題。 ? Python 是一種由 Guido van Rossum 開發的通用編程語言&#xff0c;它很快就變得非常流行&#xff0c;主要是 因為它的簡單性和代碼可讀性。它使程序員能夠用更少的代碼行…

C++ 運算符的優先級和關聯性表

C 運算符的優先級和關聯性表 1. Precedence and associativity (優先級和結合性)2. Alternative spellings (替代拼寫)3. C operator precedence and associativity table (C 運算符的優先級和關聯性表)References C documentation (C 文檔) https://learn.microsoft.com/en-us…

網絡IO模型之多路復用器.md

多路復用是什么&#xff1f;怎么理解&#xff1f; 本文主要涉及為 程序中處理網絡IO時的模型&#xff0c;對于系統內核而言網絡IO模型。這里只做普及使用 前置知識&#xff0c;什么是IO&#xff1f;怎么理解IO IO其實就是In和Out。中文翻譯是輸入和輸出&#xff0c;只要涉及到輸…

clone()方法

在Java中&#xff0c;clone() 方法是一個非常有趣且強大的工具&#xff0c;用于創建對象的一個副本。這個方法位于 Object 類中&#xff0c;因此可以被所有類使用。讓我們討論一下它的幾個要點&#xff1a; 什么是克隆&#xff1f; 克隆就是創建一個對象的新副本&#xff0c;這…

2005-2022全國及各省家庭承包耕地流轉總面積及經營耕地面積數據(無缺失)

2005-2022全國及各省家庭承包耕地流轉總面積及經營耕地面積數據&#xff08;無缺失&#xff09; 1、時間&#xff1a;2005-2022年 2、范圍&#xff1a;全國及30省 3、指標&#xff1a;家庭承包耕地流轉總面積、家庭承包經營耕地面積、土地流轉率、 4、來源&#xff1a;農村…

《web應用技術》第十一次課后作業

驗證過濾器進行權限驗證的原理。 創建Filter&#xff1a; package com.example.filter;import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException;WebFilter(urlPatterns "/*") public class DemoFilter implements Filter …

【3維BFS】個人練習-Leetcode-LCP 79. 提取咒文

題目鏈接&#xff1a;https://leetcode.cn/problems/kjpLFZ/ 題目大意&#xff1a;給一個矩陣matrix[][]&#xff0c;元素為小寫英文字母。給一個字符串mantra&#xff0c;求從矩陣的(0,0)位置開始&#xff0c;可以移動&#xff08;上下左右&#xff09;或者提取字母&#xff…

怎么搭建個人博客教程,附云主機選購指南

一、搭建個人博客教程 1. 規劃博客內容與技術棧 確定博客主題&#xff1a;首先明確博客的定位和主題&#xff0c;這將影響后續的技術選擇和內容規劃。選擇技術棧&#xff1a;根據個人偏好和技術背景&#xff0c;選擇合適的建站技術。例如&#xff0c;可以使用WordPress&#…

adobe pdf設置默認打開是滾動而不是單頁視圖

上班公司用adobe pdf&#xff0c;自己還不能安裝其它軟件。 每次打開pdf&#xff0c;總是默認單頁視圖&#xff0c;修改滾動后&#xff0c;下次打開又 一樣&#xff0c;有時候比較煩。 后面打開編輯->首選項&#xff0c; 如下修改&#xff0c;下次打開就是默認滾動了

Websocket通信實戰項目(圖片互傳應用)+PyQt界面+python異步編程(async) (上)服務器端python實現

Rqtz : 個人主頁 ?? 共享IT之美&#xff0c;共創機器未來 ? Sharing the Beauty of IT and Creating the Future of Machines Together 目錄 項目背景 ?編輯?專有名詞介紹 服務器GUI展示 功能(位置見上圖序號) 客戶端GUI展示&#xff08;h5cssjs&#xf…

flask的進階使用方法

【 一 】一對多關系 # 1 一對一 [本質就是一對多--》多的那個唯一] # 2 一對多 # 3 多對多1.1 關系 #### 一對多關系 class Hobby(Base):__tablename__ hobbyid Column(Integer, primary_keyTrue)caption Column(String(50), default籃球)def __str__(self):return sel…