container目錄 heap 包

go版本:go1.12 windows/amd64

container目錄結(jié)構(gòu)如下:

├─heap
    ├─heap.go
    ├─heap_test.go
    ├─example_intheap_test.g
    └─example_pq_test.go
├─list
    ├─list.go
    ├─list_test.go
    ├─example_test.go
└─ring
    ├─ring.go
    ├─ring_test.go
    └─example_test.go

1. heap包介紹
??為所有繼承Interface的結(jié)構(gòu)體提供操作,heap是一個(gè)根節(jié)點(diǎn)為最小值的二叉樹(shù)(最小堆)
??heap包對(duì)任意實(shí)現(xiàn)了heap接口的類型提供堆操作。
??樹(shù)的最小元素在根部,為index 0.
??heap是常用的優(yōu)先隊(duì)列的方法,要?jiǎng)?chuàng)建一個(gè)優(yōu)先隊(duì)列,要實(shí)現(xiàn)一個(gè)具有負(fù)優(yōu)先級(jí)隊(duì)列,可以通過(guò)Less方法的Heap接口,如此一來(lái)可用Push添加item,而用Pop取出隊(duì)列最高優(yōu)先級(jí)的item。(后面解釋

type Interface interface {
    sort.Interface
    Push(x interface{}) // add x as element Len()
    Pop() interface{}   // remove and return element Len() - 1.
}

// sort.Interface如下:
// A type, typically a collection, that satisfies sort.Interface can be
// sorted by the routines in this package. The methods require that the
// elements of the collection be enumerated by an integer index.
type Interface interface {
    // Len is the number of elements in the collection.
    Len() int
    // Less reports whether the element with
    // index i should sort before the element with index j.
    Less(i, j int) bool
    // Swap swaps the elements with indexes i and j.
    Swap(i, j int)
}

??其中sort.Interface用于排序,heap.Interface中Push和Pop方法分別用于插入和取出元素的操作

??heap中的方法:

func Init(h Interface)  // h初始化,按最小堆排序,時(shí)間復(fù)雜度O(n) ,n等于h.Len()
func Pop(h Interface) interface{} // 刪除并返回堆h中的最小元素(不影響約束性)。復(fù)雜度O(log(n)),n等于h.Len()。該函數(shù)等價(jià)于Remove(h, 0)。
func Push(h Interface, x interface{})  // 向堆h中插入元素x,并保持堆的約束性。復(fù)雜度O(log(n)),n等于h.Len()。
func Remove(h Interface, i int) interface{}  // 刪除堆中的第i個(gè)元素,并保持堆的約束性。復(fù)雜度O(log(n)),n等于h.Len()。
func Fix(h Interface, i int)  // 在修改第i個(gè)元素后,調(diào)用本函數(shù)修復(fù)堆,比刪除第i個(gè)元素后插入新元素更有效率。復(fù)雜度O(log(n)),n等于h.Len()。

2. heap(小頂堆) 構(gòu)造原理:
??小頂堆實(shí)際上是一個(gè)二叉樹(shù),滿足:Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]規(guī)則,即根節(jié)點(diǎn)既小于或等于左子樹(shù)的關(guān)鍵字值,又小于或等于右子樹(shù)的關(guān)鍵字值。
??由此可知, n/2 - 1之前的節(jié)點(diǎn)都為父節(jié)點(diǎn),n/2-1之后的節(jié)點(diǎn)都為葉子節(jié)點(diǎn),我們可以從 n/2 - 1節(jié)點(diǎn)開(kāi)始,依次與其左葉子節(jié)點(diǎn)h[2(n/2-1)+1]和右葉子節(jié)點(diǎn)h[2(n/2-1)+2]比較,取三者最小值做為父節(jié)點(diǎn)

func Init(h Interface) {
    // heapify
    n := h.Len()
    for i := n/2 - 1; i >= 0; i-- {
        down(h, i, n)
    }
}

func down(h Interface, i0, n int) bool {
    i := i0
    for {
        j1 := 2*i + 1
        if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
            break
        }
        j := j1 // left child
        if j2 := j1 + 1; j2 < n && h.Less(j2, j1) {
            j = j2 // = 2*i + 2  // right child
        }
        if !h.Less(j, i) {
            break
        }
        h.Swap(i, j)
        i = j
    }
    return i > i0
} 
//  將末尾元素移跟根節(jié)點(diǎn)元素交換,然后使用 down 方法來(lái)修復(fù)堆。最后Pop()取出末尾元素
func Pop(h Interface) interface{} {
    n := h.Len() - 1
    h.Swap(0, n)
    down(h, 0, n)
    return h.Pop()
}


// 每次添加新元素,若存在父節(jié)點(diǎn)則跟父節(jié)點(diǎn)比較,若小于父節(jié)點(diǎn),則交換
func Push(h Interface, x interface{}) {
    h.Push(x)
    up(h, h.Len()-1)
}
func up(h Interface, j int) {
    for {
        i := (j - 1) / 2 // parent
        if i == j || !h.Less(j, i) {
            break
        }
        h.Swap(i, j)
        j = i
    }
}

3.使用heap構(gòu)造優(yōu)先級(jí)隊(duì)列 (nsq源碼的優(yōu)先級(jí)隊(duì)列實(shí)現(xiàn)原理)
思路:通過(guò)重寫(xiě)Less()方法,取相反的優(yōu)先級(jí)比較,這樣Pop()函數(shù)每次取出的即是優(yōu)先級(jí)最高的Item.

// An Item is something we manage in a priority queue.
type Item struct {
    value    string // The value of the item; arbitrary.
    priority int    // The priority of the item in the queue.
    // The index is needed by update and is maintained by the heap.Interface methods.
    index int // The index of the item in the heap.
}

// A PriorityQueue implements heap.Interface and holds Items.
type PriorityQueue []*Item

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
    // We want Pop to give us the highest, not lowest, priority so we use greater than here.
    return pq[i].priority > pq[j].priority
}

func (pq PriorityQueue) Swap(i, j int) {
    pq[i], pq[j] = pq[j], pq[i]
    pq[i].index = i
    pq[j].index = j
}

func (pq *PriorityQueue) Push(x interface{}) {
    n := len(*pq)
    item := x.(*Item)
    item.index = n
    *pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
    old := *pq
    n := len(old)
    item := old[n-1]
    item.index = -1 // for safety
    *pq = old[0 : n-1]
    return item
}


// update modifies the priority and value of an Item in the queue.
func (pq *PriorityQueue) update(item *Item, value string, priority int) {
    item.value = value
    item.priority = priority
    heap.Fix(pq, item.index)
}

// This example creates a PriorityQueue with some items, adds and manipulates an item,
// and then removes the items in priority order.
func Example_priorityQueue() {
    // Some items and their priorities.
    items := map[string]int{
        "banana": 3, "apple": 2, "pear": 4,
    }

    // Create a priority queue, put the items in it, and
    // establish the priority queue (heap) invariants.
    pq := make(PriorityQueue, len(items))
    i := 0
    for value, priority := range items {
        pq[i] = &Item{
            value:    value,
            priority: priority,
            index:    i,
        }
        i++
    }
    heap.Init(&pq)

    // Insert a new item and then modify its priority.
    item := &Item{
        value:    "orange",
        priority: 1,
    }
    heap.Push(&pq, item)
    pq.update(item, item.value, 5)

    // Take the items out; they arrive in decreasing priority order.
    for pq.Len() > 0 {
        item := heap.Pop(&pq).(*Item)
        fmt.Printf("%.2d:%s ", item.priority, item.value)
    }
    // Output:
    // 05:orange 04:pear 03:banana 02:apple
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容