Я работаю над функциональными структурами данных Okasaki Purely и пытаюсь построить реализацию F # вещей. Я также выполняю упражнения, перечисленные в книге (некоторые из них довольно сложны). Ну, я застрял в упражнении 3.4, который требует модификации функции слияния WeightBiasedLeftistHeap таким образом, что он выполняется за один проход в отличие от исходной реализации с двумя проходами.
Я еще не мог понять, как это сделать, и надеялся на некоторые предложения. Был еще один пост здесь, на SO, где парень делает это в SML, в значительной степени вставляя функцию makeT. Я начал идти по этому маршруту (в комментариях к разделу 3.4 "Первая попытка", но отказался от этого подхода, потому что я думал, что это действительно не выполняется за один проход (он все еще идет "до тех пор, пока не дойдет до листа, а затем разматывает и восстанавливает дерево" ). Я ошибаюсь в интерпретации того, что все еще происходит слияние двух проходов?
Вот ссылка на мою полную реализацию WeightBiasedLeftistHeap.
Вот мои неудачные попытки сделать это в F #:
type Heap<'a> =
| E
| T of int * 'a * Heap<'a> * Heap<'a>
module WeightBiasedLeftistHeap =
exception EmptyException
let weight h =
match h with
| E -> 0
| T(w, _,_,_) -> w
let makeT x a b =
let weightA = weight a
let weightB = weight b
if weightA >= weightB then
T(weightA + weightB + 1, x, a, b)
else
T(weightA + weightB + 1, x, b, a)
// excercise 3.4 first try
// let rec merge3_4 l r =
// match l,r with
// | l,E -> l
// | E,r -> r
// | T(_, lx, la, lb) as lh, (T(_, rx, ra, rb) as rh) ->
// if lx <= rx then
// let right = merge3_4 lb rh
// let weightA = weight la
// let weightB = weight right
//
// if weightA >= weightB then
// T(weightA + weightB + 1, lx, la, right)
// else
// T(weightA + weightB + 1, lx, right, la)
// else
// let right = merge3_4 lh rb
// let weightA = weight ra
// let weightB = weight right
//
// if weightA >= weightB then
// T(weightA + weightB + 1, rx, ra, right)
// else
// T(weightA + weightB + 1, rx, right, ra)
// excercise 3.4 second try (fail!)
// this doesn't work, I couldn't figure out how to do this in a single pass
let merge3_4 l r =
let rec merge' l r value leftChild =
match l,r with
| l,E -> makeT value leftChild l
| E,r -> makeT value leftChild r
| T(_, lx, la, lb) as lh, (T(_, rx, ra, rb) as rh) ->
if lx <= rx then
merge' lb rh lx la //(fun h -> makeT(lx, la, h))
else
merge' lh rb rx ra //(fun h -> makeT(rx, ra, h))
match l, r with
| l, E -> l
| E, r -> r
| T(_, lx, la, lb) as lh, (T(_, rx, ra, rb) as rh) ->
let lf = fun h -> makeT(lx, la, h)
if lx <= rx then
merge' lb rh lx la // (fun h -> makeT(lx, la, h))
else
merge' lh rb rx ra // (fun h -> makeT(rx, ra, h))
let rec merge l r =
match l,r with
| l,E -> l
| E,r -> r
| T(_, lx, la, lb) as lh, (T(_, rx, ra, rb) as rh) ->
if lx <= rx then
makeT lx la (merge lb rh)
else
makeT rx ra (merge lh rb)
let insert3_4 x h =
merge3_4 (T(1,x,E,E)) h