我试图在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;
你能帮我找一下插入原语中可能出错的地方吗? 谢谢。
答案 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'
注意二项式树列表不空的情况。那里的代码说如果插入的树的等级大于列表中下一个树的等级,则将树添加到列表。这违反了表示堆的树列表按递增的排序顺序组织的假设。在比较中将标志从>
转换为<
可以解决问题。