這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
package main//@description元素流中擷取Top-K的元素,元素需實現Comple介面//@author chenbintao//@data 2017-03-3114:19初稿//2017-03-3117:44編譯驗證通過import ("fmt""log")//元素介面設計,參與排序的元素,需要實現介面內的方法type ELEM interface {//比較當前元素與o元素大小,true:大於oComple(interface{}) bool}/**TOP-K-Heap用於從資料中篩選出前K極值元素**/type TopKHeap struct {heap []ELEM //物理上採用數組實現(介面即指標)size int64 //堆大小index int64 //堆元素數(指向下一個可用)bigMode bool //是否為大頂模式}func New(size int64, bigMode bool) *TopKHeap {if size <= 0 {return nil}//構建一個指定大小的大/小頂堆this := new(TopKHeap)this.heap = make([]ELEM, size)this.size = sizethis.index = 0this.bigMode = bigModereturn this}//擷取堆容量func (this *TopKHeap) GetSize() int64 {return this.size}//擷取元素數func (this *TopKHeap) GetCount() int64 {return this.index}//入堆func (this *TopKHeap) Push(i interface{}) {if nil == i {return}var o ELEM = i.(ELEM)if this.index < this.size {//A.未滿,末尾添加,滿後建立堆this.heap[this.index] = othis.index++if this.index >= this.size {this.build()}} else {//B.已滿,替換及調整if ((!o.Comple(this.heap[0])) && this.bigMode) /*入堆元素小於大頂堆的堆頂*/ ||((o.Comple(this.heap[0])) && !this.bigMode) /*入堆元素大於小頂堆的堆頂*/ {//滿足替換條件this.heap[0] = o //替換堆頂this.adjust(0) //堆頂開始調整堆}}return}//出堆func (this *TopKHeap) Pop() (o interface{}) {if this.index <= 0 ||this.size <= 0 {return nil}//回溯到尾元素this.index--if this.index <= 0 {this.index = 0}o = this.heap[0] //擷取堆頂this.heap[0] = this.heap[this.index] //交換堆頂this.heap[this.index] = nil //刪除尾元this.adjust(0) //調整堆return o}//建堆func (this *TopKHeap) build() {//首個非葉子節點開始調整i := this.getFather(this.index - 1)for i >= 0 {this.adjust(i)i--}return}//列印堆func (this *TopKHeap) String() string {return fmt.Sprint(this.heap)}//調整堆(遞迴實現)func (this *TopKHeap) adjust(i int64) int64 {if this.checkIndex(i) < 0 {return -1}//調整左子堆(交換與遞迴調整)var child int64child = this.getLeft(i)if child > 0 &&(((this.heap[i]).Comple(this.heap[child]) && !this.bigMode /*根大於小頂堆孩子*/) ||(!(this.heap[i]).Comple(this.heap[child]) && this.bigMode /*根小於大頂堆孩子*/)) {tmp := this.heap[i]this.heap[i] = this.heap[child]this.heap[child] = tmpthis.adjust(child)}//調整右子堆(交換與遞迴調整)child = this.getRight(i)if child > 0 &&(((this.heap[i]).Comple(this.heap[child]) && !this.bigMode /*根大於小頂堆孩子*/) ||(!(this.heap[i]).Comple(this.heap[child]) && this.bigMode /*根小於大頂堆孩子*/)) {tmp := this.heap[i]this.heap[i] = this.heap[child]this.heap[child] = tmpthis.adjust(child)}return i}//判斷堆是否需要調整func (this *TopKHeap) needAdjust(root, child int64) bool {if ((this.heap[root]).Comple(this.heap[child]) && !this.bigMode /*根大於小頂堆孩子*/) ||(!(this.heap[root]).Comple(this.heap[child]) && this.bigMode /*根小於大頂堆孩子*/) {return true}return false}//擷取父節點(堆頂為0,超出容量時返回-1)func (this *TopKHeap) getFather(i int64) int64 {//(i-1)/2向下取整var j int64j = (i - 1) / 2if this.checkIndex(i) >= 0 &&this.checkIndex(j) >= 0 {return j}return -1}//擷取左孩子節點(堆頂為0,超出容量時返回-1)func (this *TopKHeap) getLeft(i int64) int64 {//(i+1)*2-1var j int64j = (i+1)*2 - 1if this.checkIndex(i) >= 0 &&this.checkIndex(j) >= 0 {return j}return -1}//擷取右孩子節點(堆頂為0,超出容量時返回-1)func (this *TopKHeap) getRight(i int64) int64 {//(i+1)*2var j int64j = (i + 1) * 2if this.checkIndex(i) >= 0 &&this.checkIndex(j) >= 0 {return j}return -1}//檢查節點的合法性(堆頂為0,超出容量時返回-1)func (this *TopKHeap) checkIndex(i int64) int64 {if i < 0 ||i >= this.size ||i >= this.index ||nil == this.heap[i] {return -1}return i}//===============================================測試程式//樣本用於排序的元素類型type Elem struct {i int}func (this Elem) Comple(i interface{}) bool {//ELEM為介面,該方法直接使用Elem類型var o Elem = i.(Elem)if this.i > o.i {return true} else {return false}}func (this *Elem) Sring() string {return fmt.Sprint(this.i)}func main() {heap := New(6, false)for i := 0; i < 10; i++ {e := Elem{i: i}heap.Push(e)log.Println(heap.String())}for heap.GetCount() > 0 {e := heap.Pop().(Elem)log.Println(e.Sring())}}
運行可參見http://studygolang.com/topics/2602
472 次點擊