优先级队列实现

Posted chenqionghe

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了优先级队列实现相关的知识,希望对你有一定的参考价值。

优先级队列的底层实现是堆(最大堆、最小堆)

一、堆的特点

  1. 完全二叉树
  2. 每个节点的值都必须大于等于或小于等于子树中节点的值(对应最大堆、最小堆)
  3. 往堆中插入和删除一个元素的时间复杂度都是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)

以上是关于优先级队列实现的主要内容,如果未能解决你的问题,请参考以下文章

线性表--08---优先队列

优先队列代码实现

基于最大堆实现最大优先队列代码

利用Vector实现优先级队列

优先队列实现dijkstra算法C++代码

堆和优先级队列2:java实现堆和优先级队列