優先級隊列的底層實現是堆(最大堆、最小堆)
一、堆的特點
- 完全二叉樹
- 每個節點的值都必須大於等於或小於等於子樹中節點的值(對應最大堆、最小堆)
- 往堆中插入和刪除一個元素的時間復雜度都是O(logn)
二、實現
最大堆和最小堆實現原理基本一樣,下面實現一個最大堆
package main
type MaxHeap struct {
array []int //數組,從下標1開始存儲數據
count int //堆中已經存儲的數據個數
size int
}
//初始化一個堆
func NewMaxHeap(size int) *MaxHeap {
obj := &MaxHeap{
size: size,
count: 0,
array: make([]int, size),
}
return obj
}
//往堆中添加一個元素
func (this *MaxHeap) Push(data int) bool {
if this.count >= this.size {
return false
}
this.array[this.count] = data
i := this.count
this.dowToUp(i)
this.count++
return true
}
//移除堆頂元素
func (this *MaxHeap) Pop() int {
if this.count == 0 {
return -1 //堆中沒有數據
}
max := this.array[0]
this.array[0] = this.array[this.count-1] //將最后一個元素放到堆頂
this.count--
this.upToDown(0) //堆化
return max
}
//獲取當前存儲元素的個數
func (this *MaxHeap) Count() int {
return this.count
}
//從下往上堆化
func (this *MaxHeap) dowToUp(i int) {
for (i-1)/2 >= 0 && this.array[i] > this.array[(i-1)/2] {
this.swap(i, (i-1)/2)
i = (i - 1) / 2
}
}
//自上往上堆化
func (this *MaxHeap) upToDown(i int) {
for {
a := this.array
n := this.count
maxPos := i
leftNode := i*2 + 1
rightNode := i*2 + 2
if leftNode < n && a[i] < a[leftNode] {
maxPos = leftNode
}
if rightNode < n && a[maxPos] < a[rightNode] {
maxPos = rightNode
}
if maxPos == i {
break
}
this.swap(i, maxPos)
i = maxPos //再檢測子節點
}
}
func (this *MaxHeap) swap(i int, j int) {
this.array[i], this.array[j] = this.array[j], this.array[i]
}
這個最大堆本質就是一個優先級從高到低的隊列,下面是測試
func main() {
//待入隊元素
a := []int{8, 7, 6, 9, 0, 5, 1, 2, 3, 4}
//new一個優先級隊列
priorityQueue := NewMaxHeap(len(a))
for i := 0; i < len(a); i++ {
priorityQueue.Push(a[i]) //依次入隊
}
//依次出隊
for priorityQueue.Count() > 0 {
fmt.Print(priorityQueue.Pop(), " ")
}
}
輸出
9 8 7 6 5 4 3 2 1 0
三、堆排序
1.每次將堆中最大的元素移到數組的末尾
2.剩下n-1個元素重新堆化
3.重復到此過程至下標1的元素
func NewMaxHeadByArray(a []int) *MaxHeap {
n := len(a)
obj := &MaxHeap{
array: a,
count: n,
size: n,
}
//堆化
for i := n / 2; i >= 0; i-- {
obj.upToDown(i)
}
return obj
}
//堆排序
func MaxHeapSort(a []int) {
heap := NewMaxHeadByArray(a)
for heap.count > 0 {
//將最大的元素移到數組最后
heap.array[0], heap.array[heap.count-1] = heap.array[heap.count-1], heap.array[0]
//減少堆的長度
heap.count--
//堆頂元素改變,重新堆化,保持堆的特性
heap.upToDown(0)
}
}
測試
func main() {
//待入隊元素
a := []int{8, 7, 6, 9, 0, 5, 1, 2, 3, 4}
MaxHeapSort(a)
fmt.Println(a)
}
輸出
[0 1 2 3 4 5 6 7 8 9]
堆排序的復雜度為O(nLogn)