MaxHeap 最大堆 MinHeap 最小堆 PriorityQueue 優先佇列實現

twisted-fate發表於2019-06-04

覆盤:

Max Heap 最大堆實現

優化了shiftDown的判斷減少了重複程式碼 , 在遍歷中做部分邊界條件終止

shiftDown 邊界定義出錯 , 正確的應該是該元素沒有左右child後終止

shiftUp的程式碼也可以優化一些減少程式碼重複判斷 , 而且邊界條件其實也沒定義好

pesudo code :


// 0 1 2 3 4 5
  [2,9,8,5,1,7]   從0開始 , 某個節點的parent=(i-1)/2 , leftP=2i+1 rightP=2i+2

MaxHeap {
    data []int    
    size int   initial 0  //沒有c++的那些helper function , 額外新增一個變數儲存size
}

size() {
    return t.size
}

isEmpty() {
    return data.size==0
}

getParentIndex(index) {
    if index==0  //root節點沒parent node
        panic()

    return (i-1)/2
}

getLeftIndex(index) {
    return 2i+1
}

getRightIndex(index) {
    return 2i+2
}

//put into arr last , then shift up
add(value) {
    append(data,value)
    t.size++
    newValueIndex = t.size-1
    t.shiftUp(newValueIndex)
}

// if parent less than current , swap , then repeat until root
shiftUp(index) {

    parent=t.getParentIndex(index)

    for parent!=0 {      // 優化,小於的時候就停止了,不需要一直遍歷到root
        if data[index]>data[parent] {
            swap
        }
        index=parent
        parent=t.getParentIndex(index)
    }
}

// store data[0] which is max , then swap last value with data[0] , execute shiftDown at zero idnex
extractMax() {
    max=data[0]

    data[0]=data[t.size()-1]
    t.size-- // soft delete 

    t.shiftDown(0)
}

swap(v1,v2) {
    tmp=v1
    v1=v2
    v2=tmp
}

    1
 3    2

// main concern is to find another bigger num float to top
// find biggest from [left,right] , if current less than it , swap , until current bigger than the biggest
shiftDown(index) {
    //優化了一遍,去除了重複程式碼
    for  index.leftChild<t.size-1  // 排除沒有child的情況

        //find  leftindex , right index
        leftIndex = t.leftChild(index)
        rightIndex= t.rightChild(index)

        //find biggest
        if t.data[leftIndex]>t.data[rightIndex] 
            bV=left
            bI=leftIndex

        if current>bV {
            break
        }

        swap(data[index],biggest)
        index=biggestIndex
}

go implementation:

package main

import "fmt"

type MaxHeap struct {
    data []int
    size int
}

func Constructor() *MaxHeap{
    return &MaxHeap{}
}

func (t *MaxHeap) sizes() int{
    return t.size
}

func (t *MaxHeap) isEmpty() bool{
    return t.size==0
}

func (t *MaxHeap) parent(index int) int{
    if index==0 {
        panic("index 0 dont have parent")
    }
    return (index-1)/2
}

func (t *MaxHeap) leftChild(index int) int{
    return 2*index+1
}

func (t *MaxHeap) rightChild(index int) int{
    return 2*index+2
}

func (t *MaxHeap) add(v int) {
    t.data=append(t.data,v)
    t.size++
    newValueIndex := t.size-1

    if newValueIndex!=0 {
        t.shiftUp(newValueIndex)
    }
}

func (t *MaxHeap) shiftUp(index int) {

    parent:=t.parent(index)

    for parent>=0 && t.data[index]>t.data[parent] {
        tmp:=t.data[index]
        t.data[index]=t.data[parent]
        t.data[parent]=tmp

        index=parent

        if parent==0 {
            break
        }
        parent= t.parent(index)
    }
}

func (t *MaxHeap) extractMax() int{
    max:=t.data[0]

    t.data[0]=t.data[t.size-1]
    t.size--
    t.data=t.data[:t.size] //移除最後一個元素,其實也可以不用刪吧
    t.shiftDown(0)
    return max
}

func (t *MaxHeap) shiftDown(index int) {

    for t.leftChild(index)<=t.size-1 && t.rightChild(index)<=t.size-1 {
        leftIndex:=t.leftChild(index)
        rightIndex:=t.rightChild(index)

        var bV int
        var bI int
        if t.data[leftIndex]>t.data[rightIndex] {
            bV=t.data[leftIndex]
            bI=leftIndex
        } else {
            bV=t.data[rightIndex]
            bI=rightIndex
        }
        if t.data[index]>bV {
            break
        }

        tmp:=t.data[index]
        t.data[index]=bV
        t.data[bI]=tmp
        index=bI
    }

}

func main() {
    m:=Constructor()
    println(m.sizes())
    m.add(1)
    m.add(2)
    m.add(3)
    m.add(4)
    m.add(5)
    m.add(6)
    m.add(7)
    m.add(8)
    fmt.Println(m.data)
    fmt.Println(m.extractMax())
    fmt.Println(m.data)
    fmt.Println(m.size)
}

Max Heap 最大堆實現

畫了個圖檢驗了一下這個簡單測試用例

Max Heap 最大堆實現

參考的老師的圖

Max Heap 最大堆實現

package main

import "fmt"

//minheap只要把maxheap的shiftup shiftdown 箭頭反轉一下就可以了 ,把小元素網上浮,大元素往下沉
type MinHeap struct {
    data []int
    size int
}

func Constructor() *MinHeap{
    return &MinHeap{}
}

func (t *MinHeap) sizes() int{
    return t.size
}

func (t *MinHeap) isEmpty() bool{
    return t.size==0
}

func (t *MinHeap) parent(index int) int{
    if index==0 {
        panic("index 0 dont have parent")
    }
    return (index-1)/2
}

func (t *MinHeap) leftChild(index int) int{
    return 2*index+1
}

func (t *MinHeap) rightChild(index int) int{
    return 2*index+2
}

func (t *MinHeap) add(v int) {
    t.data=append(t.data,v)
    t.size++
    newValueIndex := t.size-1

    if newValueIndex!=0 {
        t.shiftUp(newValueIndex)
    }
}

func (t *MinHeap) shiftUp(index int) {

    parent:=t.parent(index)

    for parent>=0 && t.data[index]<t.data[parent] {
        tmp:=t.data[index]
        t.data[index]=t.data[parent]
        t.data[parent]=tmp

        index=parent

        if parent==0 {
            break
        }
        parent= t.parent(index)
    }
}

func (t *MinHeap) extractMin() int{
    min:=t.data[0]

    t.data[0]=t.data[t.size-1]
    t.size--
    t.data=t.data[:t.size] //移除最後一個元素,其實也可以不用刪吧
    t.shiftDown(0)
    return min
}

func (t *MinHeap) shiftDown(index int) {

    for t.leftChild(index)<=t.size-1 && t.rightChild(index)<=t.size-1 {
        leftIndex:=t.leftChild(index)
        rightIndex:=t.rightChild(index)

        var bV int
        var bI int
        if t.data[leftIndex]<t.data[rightIndex] {
            bV=t.data[leftIndex]
            bI=leftIndex
        } else {
            bV=t.data[rightIndex]
            bI=rightIndex
        }
        if t.data[index]<bV {
            break
        }

        tmp:=t.data[index]
        t.data[index]=bV
        t.data[bI]=tmp
        index=bI
    }
}

func main() {
    m:=Constructor()
    m.add(1)
    m.add(2)
    m.add(3)
    m.add(4)
    m.add(5)
    m.add(6)
    m.add(7)
    m.add(8)
    fmt.Println(m.data)
    fmt.Println(m.size)
    fmt.Println(m.extractMin())
    fmt.Println(m.data)
    fmt.Println(m.size)
    fmt.Println(m.extractMin())
    fmt.Println(m.extractMin())
    fmt.Println(m.extractMin())
    fmt.Println(m.extractMin())
    fmt.Println(m.extractMin())
    fmt.Println(m.extractMin())
    fmt.Println(m.extractMin())
}

優先佇列這裡妥妥的就是一個介面卡模式的典例

package main

type PriorityQueue struct {
    maxHeap *MaxHeap
}

func (t *PriorityQueue) size() int{
    return t.maxHeap.sizes()
}

func (t *PriorityQueue) isEmpty() bool{
    return t.maxHeap.isEmpty()
}

func (t *PriorityQueue) front() int{
    if t.size()==0 {
        panic("queue is empty")
    }
    return t.maxHeap.data[0]
}

func (t *PriorityQueue) enqueue(v int){
    t.maxHeap.add(v)
}
func (t *PriorityQueue) dequeue(){
    t.maxHeap.extractMax()
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章