這篇文章是基於我看過的一篇論文,主要是關於函數式數據結構,函數式堆(優先級隊列),bootstrap
我會以本身的理解寫下來,而後論文中出現的代碼將會使用scala這們語言。數據結構
論文連接: Optimal Purely Functional Priority Queues,另一個連接: 論文。 app
緊接patr two,ide
這章介紹對合併和查找操做的優化,使得最終插入,合併,查找最小的時間複雜度均爲O(1)。函數
這裏我跳過了論文中增長全局根那一節,由於bootstrap這一節包含了增長全局根的內容。測試
首先假設原始堆的定義是:優化
a表示堆中存儲的元素類型。this
而後給出最終的bootstrap堆的定義:spa
這裏BHa表示bootstrap堆或者是一個空堆或者是Ra(R表明root),scala
Ra表示一個元素a和一個原始堆H包含其餘非空的bootstrap堆Ra的元組。
a其實就是保存堆中最小的元素,這樣查找最小的操做時間複雜度就變爲O(1)。
而這裏原始堆H選用的固然就是斜二項堆,這樣保持插入的時間複雜度O(1)。
而bootstrap堆的合併操做其實就變成將一個bootstrap堆做爲元素插入到斜二項堆中。
這裏對於斜二項堆中保存的元素類型就是Ra。
這裏的定義有遞歸的感受,讀者最好是熟悉了前兩章的內容再來看這章,
由於我是精簡不少內容,因此若是以爲我說的不清楚的,能夠看看論文解釋的很詳細。
我以爲看論文中的代碼對於個人理解頗有幫助。
如今來描述bootstrap堆的操做,這裏用f來表示斜二項堆HRa的操做,F來表示bootstrap堆BHa的操做。
FINDEMIN( <x, sh> ) = x , <x, sh>就是Ra的表示, sh 表示HRa,就是斜二項堆;
INSERT( x, sh ) = MELD( <x, empty>, sh )
MELD( <x1, sh1>, <x2, sh2> ) = < x1, insert( <x2, sh2>, sh1 ) > if x1 <= x2
MELD( <x1, sh1>, <x2, sh2> ) = < x2, insert( <x1, sh1>, sh2 ) > if x2 < x1
DELETEMIN( <x, sh> ) = <y, meld( sh1, sh2 )>
其中 <y, sh1> = findMin( sh )
sh2 = deleteMin( sh )
咱們能夠看到
查找最小的操做FINDMIN明顯時間複雜度爲O(1),而對於合併操做MELD,時間複雜度的爲O(1),由於斜二項堆的
插入操做是O(1),而插入操做其實就是化成合並操做MELD,因此時間複雜度爲O(1),而對於刪除最小操做,時間複雜
度是O(log n),由於對於斜二項堆findMin和deleteMin這兩項的操做時間複雜度都是O(log n)。
因爲論文中的代碼用的是ML語言,將之改爲scala花了很多功夫:
trait BootstrapSkewBinomialHeap extends Heap { //Rooted定義了斜二項堆的元素類型 trait Rooted extends Heap { //RootQ就是上面定義的Ra,h表示堆的類型 //當該trait和斜二項堆trait混合的時候,就表示爲斜二項堆的堆類型H //就是下面的RootedHeap case class RootQ( x: BootstrapSkewBinomialHeap.this.A, h: H) override type A = RootQ object AgeOrdering extends Ordering[RootQ] { def compare( a: RootQ, b: RootQ ) = BootstrapSkewBinomialHeap.this.ord.compare( a.x, b.x ) } //由於堆的元素類型變爲RootQ,因此需提供相應的元素比較方法 override def ord = AgeOrdering } //root斜二項堆 val RootedHeap = new Rooted with SkewBinomialHeap //表示空bootstrap堆 case class Empty( msg: String ) //bootstrap堆的定義,或者是一個空堆,或者是一個RootQ類型 //用scala的Either類型來描述 override type H = Either[Empty, RootedHeap.RootQ] override def empty = Left( Empty( "empty" ) ) override def isEmpty( ts: H ) = ts match { case Left( _ ) => true case Right( _ ) => false } //bootstrap堆的插入操做可化爲合併操做 override def insert( x: A, ts: H ): H = meld( Right( RootedHeap.RootQ( x, RootedHeap.empty ) ), ts ) override def meld( ts1: H, ts2: H ) = ( ts1, ts2 ) match { case ( Left( Empty( _ ) ), ts ) => ts case ( ts, Left( Empty( _ ) ) ) => ts case ( Right( RootedHeap.RootQ( x1, h1: RootedHeap.H ) ), Right( RootedHeap.RootQ( x2, h2: RootedHeap.H ) ) ) => //當兩個bootstrap堆都非空的時候 //比較兩個堆的根,較小的根做爲新堆的根 //根較大的堆做爲元素插入到根較小的斜二項堆中 if ( ord.lteq( x1, x2 ) ) Right(RootedHeap.RootQ(x1, RootedHeap.insert(ts2.right.get, h1))) else Right(RootedHeap.RootQ(x2, RootedHeap.insert(ts1.right.get, h2))) } override def findMin( ts: H ) = ts match { case Left( Empty( _ ) ) => throw new NoSuchElementException("min of empty heap") case Right( RootedHeap.RootQ( x, h ) ) => x } override def deleteMin( ts: H ) = ts match { case Left( Empty( _ ) ) => throw new NoSuchElementException("delete min of empty heap") case Right( RootedHeap.RootQ( x, h ) ) => if ( RootedHeap.isEmpty( h ) ) Left( Empty( "no element left" ) ) else { //先查找斜二項堆h的最小元素(y, h1) //而後刪除斜二項堆h的最小元素 //最後返回新bootstrap堆,根爲y,斜二項堆爲h1和h2的合併 val RootedHeap.RootQ( y, h1 ) = RootedHeap.findMin( h ) val h2 = RootedHeap.deleteMin( h ) Right( RootedHeap.RootQ( y, RootedHeap.meld( h1, h2 ) ) ) } } }
我以爲這個表達更加清晰(新增2013-12-16):
trait BootstrapSkewBinomialHeap extends Heap { trait Rooted extends Heap { //這樣定義是爲了將空的bootstrap堆和非空bootstrap堆統一塊兒來 trait RootType case class RootQ( x: BootstrapSkewBinomialHeap.this.A, h: H) extends RootType case object Empty extends RootType override type A = RootQ object AgeOrdering extends Ordering[RootQ] { def compare( a: RootQ, b: RootQ ) = BootstrapSkewBinomialHeap.this.ord.compare( a.x, b.x ) } override def ord = AgeOrdering } val RootedHeap = new Rooted with SkewBinomialHeap //這樣就不用Either來表示了 override type H = RootedHeap.RootType //這樣表示空堆更加天然和可讀 override def empty = RootedHeap.Empty override def isEmpty( ts: H ) = ts match { case RootedHeap.Empty => true case RootedHeap.RootQ(_, _) => false } override def insert( x: A, ts: H ): H = meld( RootedHeap.RootQ( x, RootedHeap.empty ), ts ) override def meld( ts1: H, ts2: H ) = ( ts1, ts2 ) match { case ( RootedHeap.Empty, ts ) => ts case ( ts, RootedHeap.Empty ) => ts case ( RootedHeap.RootQ( x1, h1: RootedHeap.H ), RootedHeap.RootQ( x2, h2: RootedHeap.H ) ) => if ( ord.lteq( x1, x2 ) ) RootedHeap.RootQ(x1,RootedHeap.insert(ts2.asInstanceOf[RootedHeap.RootQ],h1)) else RootedHeap.RootQ(x2,RootedHeap.insert(ts1.asInstanceOf[RootedHeap.RootQ],h2)) } override def findMin( ts: H ) = ts match { case RootedHeap.Empty => throw new NoSuchElementException("min of empty heap") case RootedHeap.RootQ( x, h ) => x } override def deleteMin( ts: H ) = ts match { case RootedHeap.Empty => throw new NoSuchElementException("delete min of empty heap") case RootedHeap.RootQ( x, h ) => if ( RootedHeap.isEmpty( h ) ) RootedHeap.Empty else { val RootedHeap.RootQ( y, h1 ) = RootedHeap.findMin( h ) val h2 = RootedHeap.deleteMin( h ) RootedHeap.RootQ( y, RootedHeap.meld( h1, h2 ) ) } } }
這幾天又學到了scala新的技巧,以爲能夠運用在bootstrap堆的定義上,
其實就是個小技巧,可讓代碼更簡潔(新增2013-12-21):
trait BootstrapSkewBinomialHeap extends Heap { trait Rooted extends Heap {//。。。沒有變化} val RootedHeap = new Rooted with SkewBinomialHeap //import 這一句就是技巧,對比上面發現 //以前表示繼承RootType的RootQ和Empty前面都要加RootedHeap //如今不用了,代碼更簡潔可讀 import RootedHeap._ override type H = RootType override def empty = Empty override def isEmpty( ts: H ) = ts match { case Empty => true case RootQ(_, _) => false } override def insert( x: A, ts: H ): H = meld( RootQ( x, RootedHeap.empty ), ts ) override def meld( ts1: H, ts2: H ) = ( ts1, ts2 ) match { case ( Empty, ts ) => ts case ( ts, Empty ) => ts case ( RootQ( x1, h1: RootedHeap.H ), RootQ( x2, h2: RootedHeap.H ) ) => if ( ord.lteq( x1, x2 ) ) RootQ( x1, RootedHeap.insert( ts2.asInstanceOf[RootQ], h1) ) else RootQ( x2, RootedHeap.insert( ts1.asInstanceOf[RootQ], h2 ) ) } override def findMin( ts: H ) = ts match { case Empty => throw new NoSuchElementException("min of empty heap") case RootQ( x, h ) => x } override def deleteMin( ts: H ) = ts match { case Empty => throw new NoSuchElementException("delete min of empty heap") case RootQ( x, h ) => if ( RootedHeap.isEmpty( h ) ) Empty else { val RootQ( y, h1 ) = RootedHeap.findMin( h ) val h2 = RootedHeap.deleteMin( h ) RootQ( y, RootedHeap.meld( h1, h2 ) ) } } }
object Test { def main(args: Array[String]): Unit = { //這裏新建一個元素類型是Int的bootstrap堆 val heap = new BootstrapSkewBinomialHeap with IntHeap //依次插入元素,其實認真觀察,發現和傳統的數據結構相比, //每次操做以後原來的版本和新的版本同時存在,並不想傳統的數據結構, //更新操做以後,原來的版本就找不回來了。 val heap1 = heap.insert(1, heap.empty) val heap2 = heap.insert(10, heap1) val heap3 = heap.insert(-1, heap2) val heap4 = heap.insert(-11, heap3) val heap5 = heap.insert(3, heap4) val heap6 = heap.insert(2, heap5) println(s"insert number: 1, 10, -1, -11, 3, 2") println(s" heap one findMin: ${heap.findMin(heap1)}") println(s" heap two findMin: ${heap.findMin(heap2)}") println(s" heap three findMin: ${heap.findMin(heap3)}") println(s" heap four findMin: ${heap.findMin(heap4)}") println(s" heap five findMin: ${heap.findMin(heap5)}") println(s" heap six findMin: ${heap.findMin(heap6)}") val meldheap26 = heap.meld(heap2, heap6) println(s"meld heap two and six then findMin: ${heap.findMin(heap6)}") val heap7 = heap.deleteMin(heap6) println(s"deleteMin heap six and then findMin: ${heap.findMin(heap7)}") val heap8 = heap.deleteMin(heap7) println(s"deleteMin heap seven and then findMin: ${heap.findMin(heap8)}") } }
結果:
object Test { trait StringHeap extends Heap { override type A = String override def ord = scala.math.Ordering.String } def main(args: Array[String]): Unit = { //元素類型是String的bootstrap堆 val heap = new BootstrapSkewBinomialHeap with StringHeap val heap1 = heap.insert("my", heap.empty) val heap2 = heap.insert("name", heap1) val heap3 = heap.insert("is", heap2) val heap4 = heap.insert("ldpe2g", heap3) val heap5 = heap.insert("hexie", heap4) val heap6 = heap.insert("fake", heap5) println(s"insert String: my, name, is, ldpe2g, hexie, fake") println(s" heap one findMin: ${heap.findMin(heap1)}") println(s" heap two findMin: ${heap.findMin(heap2)}") println(s" heap three findMin: ${heap.findMin(heap3)}") println(s" heap four findMin: ${heap.findMin(heap4)}") println(s" heap five findMin: ${heap.findMin(heap5)}") println(s" heap six findMin: ${heap.findMin(heap6)}") val meldheap26 = heap.meld(heap2, heap6) println(s"meld heap two and six then findMin: ${heap.findMin(heap6)}") val heap7 = heap.deleteMin(heap6) println(s"deleteMin heap six and then findMin: ${heap.findMin(heap7)}") val heap8 = heap.deleteMin(heap7) println(s"deleteMin heap seven and then findMin: ${heap.findMin(heap8)}") } }
結果: