• 优先级队列实现


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

    一、堆的特点

    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)

  • 相关阅读:
    confluence重置admin密码
    oracle 11g密码永不过期
    GCC编译器使用
    Emacs常用命令汇总
    bash shell命令(1)
    进程管理3--经典的进程同步问题
    进程管理2--进程的同步与信号量
    C安全问题与指针误用
    C迷途指针
    进程管理1--进程的概念与操作
  • 原文地址:https://www.cnblogs.com/chenqionghe/p/12161365.html
Copyright © 2020-2023  润新知