scala寫算法-用小根堆解決topK
阿新 • • 發佈:2017-12-24
app unit roo ast atm mark 構建 操作 mnt
topK問題是指從大量數據中獲取最大(或最小)的k個數,比如從全校學生中尋找成績最高的500名學生等等.
本問題可采用小根堆解決.思路是先把源數據中的前k個數放入堆中,然後構建堆,使其保持堆序(可以簡單的看成k次insert操作).然後從源數據中的第k個數據之後的每個元素與堆的根節點(小根堆得root是最小的)比較,如果小於root,那麽直接pass;如果大於,則執行headp.deleteMin
,然後把該元素插入堆中並再次保持堆序.保持堆序需要涉及上濾與下濾的過程.
樣例為:
object Main extends App{
val array=Array(0,14,16,19,3,3768,345 ,3,343,545,455,7567,657,67,65756,756,756,756,7657,657,657,4,534,535,345343,423,4,46546,546,544,546,546,345,345,435,34534,53,5345,45,45,435,43,54,35,435,435,34,5,435,45,65,65,6576,7,65,56,7,45,43,543,53,453,45,345,34)
//數組從1開始
val k=3
val heap=new Heap
1 to k foreach(i=>heap.insert(array(i)))
k+1 to array.length-1 foreach(i=>{
while (heap.getSize>10){
heap.deleteMin
}
if(array(i)>heap.getMin){
heap.deleteMin
heap.insert(array(i))
}
})
heap.print
}
再來說說,Heap
是如何實現的
運用scala常常遇到這樣的選擇:變量的變與不變,這是一個問題.
還有for
推導式,實際上是map
flatMap
等的語法糖.
代碼:
class Heap {
type T=Int
private var size=0
val elemnts=new Array[T](200) // 把index=0處的位置空出 2n 2n+1 n/2
def getSize:Int=return size
def insert(x:T):Unit={
def loop(i:Int):Int={
if(elemnts(i/2)<=x)
return i
elemnts(i)=elemnts(i/2)
loop(i/2)
}
val i=loop(size+1)
elemnts(i)=x
size+=1
}
def deleteMin:T={
def loop(i:Int):Int={
if(i>size) return i/2
val left=elemnts(2*i)
val right=elemnts(2*i+1)
if(left<right){
elemnts(i)=left
loop(i*2)
}else{
elemnts(i)=right
loop(2*i+1)
}
}
val result=elemnts(1)
val last=elemnts(size)
val i=loop(1)
elemnts(i)=last
size-=1
return result
}
def print:Unit= 1 to size foreach(i=>println(elemnts(i)))
def getMin:T=return elemnts(1)
//代碼親測無誤
}
在實現insert
與deleteMin
時,由於scala並沒有break
關鍵字(雖然你可以使用Breakable
這個類實現,實際上通過拋出異常模擬break,不靈活),為實現上慮(insert),考慮用遞歸來模擬for循環.
代碼:
def insert(x:T):Unit={
def loop(i:Int):Int={
if(elemnts(i/2)<=x)
return i //如果父親節點比待插入值x小,則本節點應該插入x
elemnts(i)=elemnts(i/2) //上慮
loop(i/2)
}
val i=loop(size+1) //返回待x插入的位置
elemnts(i)=x
size+=1
}
相比從c語言版,基於scala的代碼還是容易記憶與相當穩健:
void insert(Element x,Heap* h){
int i=0;
if(isFull(h))
error("full");
for(i=++h->size;h->elements[i/2]>x;i/=2)
h->elements[i]=h->elements[i/2];
h->elements[i]=x;
}
scala寫算法-用小根堆解決topK