Je suis auto-étudiant Okasaki's Purely Functional Data Structures, now on exercise 3.4, qui demande de raisonner et de mettre en œuvre un tas gauchiste biaisé par le poids. Ceci est ma mise en œuvre de base:Heaps gauchistes avec biais de poids: avantages de la version descendante de la fusion?
(* 3.4 (b) *)
functor WeightBiasedLeftistHeap (Element : Ordered) : Heap =
struct
structure Elem = Element
datatype Heap = E | T of int * Elem.T * Heap * Heap
fun size E = 0
| size (T (s, _, _, _)) = s
fun makeT (x, a, b) =
let
val sizet = size a + size b + 1
in
if size a >= size b then T (sizet, x, a, b)
else T (sizet, x, b, a)
end
val empty = E
fun isEmpty E = true | isEmpty _ = false
fun merge (h, E) = h
| merge (E, h) = h
| merge (h1 as T (_, x, a1, b1), h2 as T (_, y, a2, b2)) =
if Elem.leq (x, y) then makeT (x, a1, merge (b1, h2))
else makeT (y, a2, merge (h1, b2))
fun insert (x, h) = merge (T (1, x, E, E), h)
fun findMin E = raise Empty
| findMin (T (_, x, a, b)) = x
fun deleteMin E = raise Empty
| deleteMin (T (_, x, a, b)) = merge (a, b)
end
Maintenant, 3.4 (c) & (d), il demande:
Actuellement,
merge
fonctionne en deux passe: une passe descendante consistant appels àmerge
, et une passe ascendante consistant en des appels à la fonction auxiliaire,makeT
. Modifiermerge
à fonctionner dans une seule passe, top-down. Quels avantages aurait la version descendante demerge
dans un environnement paresseux? Dans un environnement simultané ?
j'ai changé la fonction merge
simplement inline makeT
, mais je ne vois pas les avantages, donc je pense que je ne l'ai pas compris l'esprit de ces parties de l'exercice. Qu'est-ce que je rate?
fun merge (h, E) = h
| merge (E, h) = h
| merge (h1 as T (s1, x, a1, b1), h2 as T (s2, y, a2, b2)) =
let
val st = s1 + s2
val (v, a, b) =
if Elem.leq (x, y) then (x, a1, merge (b1, h2))
else (y, a2, merge (h1, b2))
in
if size a >= size b then T (st, v, a, b)
else T (st, v, b, a)
end
Je pense que j'ai compris un point en ce qui concerne l'évaluation paresseuse. Si je ne pas utiliser la fusion récursive pour calculer la taille, l'appel récursif doit pas être évalué jusqu'à ce que l'enfant est nécessaire:
fun merge (h, E) = h
| merge (E, h) = h
| merge (h1 as T (s1, x, a1, b1), h2 as T (s2, y, a2, b2)) =
let
val st = s1 + s2
val (v, ma, mb1, mb2) =
if Elem.leq (x, y) then (x, a1, b1, h2)
else (y, a2, h1, b2)
in
if size ma >= size mb1 + size mb2
then T (st, v, ma, merge (mb1, mb2))
else T (st, v, merge (mb1, mb2), ma)
end
Est-ce tout? Cependant, je ne suis pas sûr de la concurrence.