php topk,堆实现的Top-K算法,元素流中筛选极值集合-博文

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:大于o

Comple(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 = size

this.index = 0

this.bigMode = bigMode

return 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] = o

this.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 int64

child = 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] = tmp

this.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] = tmp

this.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 int64

j = (i - 1) / 2

if this.checkIndex(i) >= 0 &&

this.checkIndex(j) >= 0 {

return j

}

return -1

}

//获取左孩子节点(堆顶为0,超出容量时返回-1)

func (this *TopKHeap) getLeft(i int64) int64 {

//(i+1)*2-1

var j int64

j = (i+1)*2 - 1

if this.checkIndex(i) >= 0 &&

this.checkIndex(j) >= 0 {

return j

}

return -1

}

//获取右孩子节点(堆顶为0,超出容量时返回-1)

func (this *TopKHeap) getRight(i int64) int64 {

//(i+1)*2

var j int64

j = (i + 1) * 2

if 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())

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值