Haskell中的二项式堆实现

时间:2018-05-14 14:59:58

标签: haskell

我试图在Haskell中实现二项式堆,使用了这本书" Purely Functional Data Structures"克里斯冈崎。

{- Implemetation of Binomial Heap-}
module BinomialHeap where

 {- Definition of a Binomial Tree -}
 data BTree a = Node Int a ([BTree a]) deriving Show

 {- Definition of a Binomial Heap -}
 data BHeap a = Heap [BTree a] deriving Show

 empty :: BHeap a
 empty = Heap []


 {- Linking function tree -}
    -- w/ larger root is
    --  linked w/ tree w/ lower root  -}
 link :: Ord a => BTree a -> BTree a -> BTree a
 link t1@(Node r x1 c1) t2@(Node _ x2 c2) =
    if x1 < x2 then
        Node (r+1) x1 (t2:c1)
    else
        Node (r+1) x2 (t1:c2)

 root :: BTree a -> a
 root (Node _ x _) = x

 {- Gives the rank of the Binomial Tree-} 
 rank :: BTree a -> Int 
 rank (Node r _ _ ) = r

 {- Insertion in the tree -}
    -- Create a new singl. tree
    -- Step through the existing trees in increasing order
    -- until we find a missing rank
    -- link tree of equal ranks
    -- atm it's O(log n)
 insTree :: Ord a => BTree a -> [BTree a] -> [BTree a]
 insTree t [] = [t]
 insTree t ts1@(t1':ts1') =
     if rank t > rank t1' then
        t:ts1
     else
        insTree (link t t1') ts1'

 insert :: Ord a => BHeap a -> a -> BHeap a
 insert (Heap ts) x = Heap $ insTree (Node 0 x []) ts

 {- Merge of Heaps-}
    --  We step through both list of tree in increasing order
    -- link tree of equal root
 merge :: Ord a => [BTree a] -> [BTree a] -> [BTree a]
 merge [] ts = ts 
 merge ts [] = ts
 merge ts1@(t1:ts1') ts2@(t2:ts2') = 
    if rank t1 < rank t2 then
        t1:merge ts1' ts2
    else if rank t2 < rank t1 then
        t2:merge ts1 ts2'
    else 
        insTree (link t1 t2) (merge ts1' ts2')


 sampleHeap :: BHeap Int
 sampleHeap = foldl insert empty [1, 2, 3]

问题是插入给了我一个不对的输出:

Heap [Node 1 1 [Node 0 3 [],Node 0 2 []]]

插入原语可能不正确。冈崎说:

&#34;要将新元素插入堆中,我们首先创建一个新的单例树(等级0)。然后我们按照排名的顺序逐步遍历现有的树,直到我们找到缺失的排名,连接相同等级的树。每个链接对应一个进位二进制算术&#34;

你能帮我找一下插入原语中可能出错的地方吗? 谢谢。

1 个答案:

答案 0 :(得分:1)

从冈崎的论文第71页(https://www.cs.cmu.edu/~rwh/theses/okasaki.pdf):

  

由于后来会变得明确的原因,我们保留了清单   树木按排名递增的顺序代表堆,但保持不变   表示节点子节点的树的列表   排名顺序。

根据这句话,让我们看一下你的insTree函数:

 insTree :: Ord a => BTree a -> [BTree a] -> [BTree a]
 insTree t [] = [t]
 insTree t ts1@(t1':ts1') =
     if rank t > rank t1' then
        t:ts1
     else
        insTree (link t t1') ts1'

注意二项式树列表不空的情况。那里的代码说如果插入的树的等级大于列表中下一个树的等级,则将树添加到列表。这违反了表示堆的树列表按递增的排序顺序组织的假设。在比较中将标志从>转换为<可以解决问题。