Golang中堆排序的實(shí)現(xiàn)
堆排序
堆的概念:
堆是一棵基于數(shù)組實(shí)現(xiàn)的特殊的完全二叉樹,這棵二叉樹的每個(gè)節(jié)點(diǎn)的值必須大于或小于它的兩個(gè)子節(jié)點(diǎn)。大頂堆
是每個(gè)節(jié)點(diǎn)的值必須大于它的兩個(gè)子節(jié)點(diǎn),小頂堆
則相反。
堆的頂點(diǎn)必定是ta的最大值或最小值
堆在數(shù)組中的存儲(chǔ)形式:
滿足完全二叉樹的情況下,數(shù)組中的每個(gè)元素依次插入堆中。如圖:
堆[9,8,9,8,7,6,4,1,2,0]
的存儲(chǔ)形式是這樣的
堆的性質(zhì):
假定數(shù)組nums
的長(zhǎng)度為leng
堆的最后一個(gè)節(jié)點(diǎn)的父節(jié)點(diǎn)下標(biāo)為:
leng/2-1
任何一個(gè)下標(biāo)為
n
的節(jié)點(diǎn)的左右子節(jié)點(diǎn)下標(biāo)為:左子節(jié)點(diǎn)ln = n*2+1
,右子節(jié)點(diǎn)rn = n*2+2
。前提是ln
和rn
小于leng-1
,即沒(méi)有下標(biāo)溢出,若溢出表明沒(méi)有該子節(jié)點(diǎn)
從數(shù)組到堆的構(gòu)建:
大頂堆為例:
先將數(shù)組以此插入完全二叉樹中,形成一顆完全二叉樹。(這步什么也不用再,看上圖,腦補(bǔ))
堆的構(gòu)建是從右往左、自下而上的。從最后一個(gè)節(jié)點(diǎn)的父節(jié)點(diǎn)leng/2-1
開(kāi)始依次遞減。
- 判斷左右子節(jié)點(diǎn)的是否存在
- 判斷是否需要替換。子節(jié)點(diǎn)的值是否大于當(dāng)前節(jié)點(diǎn)的值
- 如果替換,那么被替換的子節(jié)點(diǎn)也要左一次堆的構(gòu)建
得到個(gè)堆
代碼實(shí)現(xiàn)
func buildHeep(nums []int, len int) { // 找到最后一個(gè)節(jié)點(diǎn)的父節(jié)點(diǎn) parent := len/2 - 1 for parent >= 0 { heapify(nums, parent, len) parent-- } } func heapify(nums []int, parent, len int) { // 判斷兩個(gè)子節(jié)點(diǎn)是否比父節(jié)點(diǎn)大,如果是的話替換 max := parent lson := parent*2 + 1 rson := parent*2 + 2 if lson < len && nums[lson] > nums[max] { // 左節(jié)點(diǎn)是否大于父節(jié)點(diǎn) max = lson } if rson < len && nums[rson] > nums[max] { // 右節(jié)點(diǎn)是否大于父節(jié)點(diǎn) max = rson } if parent != max { swap(&nums[max], &nums[parent]) heapify(nums, max, len) } } nums :=[]int{3, 5, 3, 0, 8, 6} buildHeep(nums,len(nums)) // 結(jié)果 : [8 5 6 0 3 3]
堆排序:
大頂堆為例:
得到堆之后只能確定一個(gè)最值,即頂點(diǎn)是最大值。繼而:
將頂點(diǎn)和最后一個(gè)點(diǎn)調(diào)換位置,最后一個(gè)節(jié)點(diǎn)變?yōu)樽畲笾?/p>
數(shù)組下標(biāo)為0至倒數(shù)第二位即最大值前一位,再做一次堆構(gòu)建,又可以獲得一個(gè)最大值
繼續(xù)以上步驟,這一次的最后一位是在上一次的基礎(chǔ)上的
將頂點(diǎn)和最后一個(gè)點(diǎn)調(diào)換位置,最后一個(gè)節(jié)點(diǎn)變?yōu)樽畲笾?/p>
數(shù)組下標(biāo)為0至倒數(shù)第二位即最大值前一位,再做一次堆構(gòu)建,又可以獲得一個(gè)最大值
直到遍歷到數(shù)組長(zhǎng)度為2,得到排序后的數(shù)組
func HeapSort(nums []int) []int { // 堆排序,只能確認(rèn)第一次個(gè)數(shù)是最大或最小的 // 調(diào)換第一個(gè)元素和最后一個(gè)元素位置、從0倒數(shù)第二個(gè)繼續(xù)堆排序 i := len(nums) for i > 1 { buildHeep(nums, i) swap(&nums[0], &nums[i-1]) i-- } return nums }
一行為一次堆疊化
完整代碼:
// heap.go package structpk import "fmt" /* 給定整數(shù)數(shù)組nums和k, 請(qǐng)返回?cái)?shù)組中第k個(gè)最大元素, 請(qǐng)注意,你需要找的是數(shù)組排序后的第k個(gè)最大元素, 而不是第k個(gè)不同的元素 */ func swap(a, b *int) { *a, *b = *b, *a } func HeapSort(nums []int) []int { // 堆排序,只能確認(rèn)第一次個(gè)數(shù)是最大或最小的 // 調(diào)換第一個(gè)元素和最后一個(gè)元素位置、從0倒數(shù)第二個(gè)繼續(xù)堆排序 i := len(nums) for i > 1 { buildHeep(nums, i) swap(&nums[0], &nums[i-1]) i-- } return nums } func buildHeep(nums []int, len int) { // 找到最后一個(gè)節(jié)點(diǎn)的父節(jié)點(diǎn) parent := len/2 - 1 for parent >= 0 { heapify(nums, parent, len) parent-- } fmt.Println(nums[0:len]) } func heapify(nums []int, parent, len int) { // 判斷兩個(gè)子節(jié)點(diǎn)是否比父節(jié)點(diǎn)大,如果是的話替換 max := parent lson := parent*2 + 1 rson := parent*2 + 2 if lson < len && nums[lson] > nums[max] { // 左節(jié)點(diǎn)是否大于父節(jié)點(diǎn) max = lson } if rson < len && nums[rson] > nums[max] { // 右節(jié)點(diǎn)是否大于父節(jié)點(diǎn) max = rson } if parent != max { swap(&nums[max], &nums[parent]) heapify(nums, max, len) } }
// main.go: package main import ( "demo/structpk" "fmt" ) func main() { fmt.Println(structpk.HeapSort([]int{ 3, 5, 3, 0, 8, 6, })) }
到此這篇關(guān)于Golang中堆排序的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Golang 堆排序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺析Go使用定時(shí)器時(shí)如何避免潛在的內(nèi)存泄漏陷阱
這篇文章來(lái)和大家一起探討一下Go?中如何高效使用?timer,特別是與select?一起使用時(shí),如何防止?jié)撛诘膬?nèi)存泄漏問(wèn)題,感興趣的可以了解下2024-01-01Go?實(shí)現(xiàn)?WebSockets之創(chuàng)建?WebSockets
這篇文章主要介紹了Go?實(shí)現(xiàn)?WebSockets之創(chuàng)建?WebSockets,文章主要探索?WebSockets,并簡(jiǎn)要介紹了它們的工作原理,并仔細(xì)研究了全雙工通信,想了解更多相關(guān)內(nèi)容的小伙伴可以參考一下2022-04-04golang實(shí)現(xiàn)基于channel的通用連接池詳解
這篇文章主要給大家介紹了關(guān)于golang實(shí)現(xiàn)基于channel的通用連接池的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-02-02解析Go語(yǔ)言編程中的struct結(jié)構(gòu)
這篇文章主要介紹了Go語(yǔ)言編程中的struct結(jié)構(gòu),是Go語(yǔ)言入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-10-10Golang 函數(shù)執(zhí)行時(shí)間統(tǒng)計(jì)裝飾器的一個(gè)實(shí)現(xiàn)詳解
這篇文章主要介紹了Golang 函數(shù)執(zhí)行時(shí)間統(tǒng)計(jì)裝飾器的一個(gè)實(shí)現(xiàn)詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-03-03一起來(lái)用GoLand開(kāi)發(fā)第一個(gè)Go程序
當(dāng)您在編輯器中工作時(shí)GoLand 會(huì)分析您的代碼,尋找優(yōu)化方法,并檢測(cè)潛在和實(shí)際問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于用GoLand開(kāi)發(fā)第一個(gè)Go程序的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12Windows系統(tǒng)中搭建Go語(yǔ)言開(kāi)發(fā)環(huán)境圖文詳解
GoLand?是?JetBrains?公司推出的商業(yè)?Go?語(yǔ)言集成開(kāi)發(fā)環(huán)境(IDE),這篇文章主要介紹了Windows系統(tǒng)中搭建Go語(yǔ)言開(kāi)發(fā)環(huán)境詳解,需要的朋友可以參考下2022-10-10深入了解Golang網(wǎng)絡(luò)編程N(yùn)et包的使用
net包主要是增加?context?控制,封裝了一些不同的連接類型以及DNS?查找等等,同時(shí)在有需要的地方引入?goroutine?提高處理效率。本文主要和大家分享下在Go中網(wǎng)絡(luò)編程的實(shí)現(xiàn),需要的可以參考一下2022-07-07