module QuickQueueFunctor (Q : Prioqueue.CYCLE_QUEUE) : (Prioqueue.PRIOQUEUE) = struct (* this is here only because of tester. you can delete fhis line, if you won't be using PRIOQUEUE module type, because Q.priority is used instead *) type priority = int type 'a t = Node of 'a node | Leaf of 'a Q.queue and 'a node = { priority : priority; left : 'a t ref; right : 'a t ref; } (* A lot of code here is imperative, and so the queue itself is temporary, it changes in time, unlike fully functional data structures *) type 'a queue = Root of 'a Q.queue ref * 'a t ref (* this code might look better if translated into objects... for future *) (* for sake of my sanity - i declare to all thou readers, all functins available outside this module take no references as parameters. BUT! it doesn't mean, that objects passed as their parameters do preserve their status quo. mostly they do change and propably become useless. only funtions results are proper *) let empty() = let q = ref (Q.empty()) in Root (q, ref (Leaf !q)) exception Unproper_use_of_queue let is_empty = function Root (_, q) -> match !q with Leaf p -> Q.is_empty p | _ -> false exception Queue_is_full (* Tricky come's into action! *) (* sometimes I wonder how come this code works... *) (* ---------- I N S E R T ----------- *) let insert = fun ( Root(min,que) ) p a -> (* takes a leaf reference and divides it into a node and dwo leafs *) let divide nod = ( function (prio, l, r) -> Node { priority = prio; left = ref (Leaf l); right = ref (Leaf r); } ) ( Q.divide ( match !(nod) with Leaf q -> q | _ -> raise Unproper_use_of_queue ) ) (* when dividing most left leaf and afterwards if inserting not into new most left leaf, ins doesnt remember that most left leaf was changed *) and divided_most_left_leaf nod = match !(nod) with Node e -> begin match !(e.left) with Leaf q -> (ref q, true) | _ -> raise Unproper_use_of_queue end | _ -> raise Unproper_use_of_queue in (* returns reference to cycle queue into whitch it added new element *) (* first parameter is where it should insert, second is if most left leaf was changed *) let ins nodi mmi = let rec rec_ins nd mm = begin match !nd with Leaf q -> begin (ref (Q.insert q p a), mm); (* might end with an exception *) end | Node nod -> if p < nod.priority then try rec_ins nod.left mm with Q.Queue_is_full -> (* so nod.left is a leaf! *) begin nod.left := divide nod.left; let ins_result = rec_ins nod.left mm in if mm then divided_most_left_leaf nod.left else ins_result end else try rec_ins nod.right false with Q.Queue_is_full -> (* so nod.right is a leaf! *) begin nod.right := divide nod.right; rec_ins nod.right false; end end in try rec_ins nodi mmi with Q.Queue_is_full -> (* so ins was taken on a leaf at first *) begin nodi := divide nodi; let _ = rec_ins nodi true in divided_most_left_leaf nodi end; in let (new_min, modified_min) = ins que true in (* now it's time to check if the minimum has changed *) if modified_min then Root(new_min, que) else Root(min, que) (* take last updated and check if it's a minimum *) (* ----- end of I N S E R T ------- *) exception Queue_is_empty (* ---- D E L E T E M I N ----- *) let rec delete_min = let rec give_most_left_node q = match !q with Leaf _ -> raise Queue_is_empty | Node n -> match !(n.left) with Leaf _ -> q | _ -> give_most_left_node n.left in (* erase most left leaf from the tree (rearranging nodes) and return reference to new most left leaf *) let rec rebuild q = let nod = give_most_left_node q in match !nod with Node n -> begin nod := !(n.right); (* leaf erased. now let's find another min *) match !nod with Leaf _ -> nod | Node m -> try match !(give_most_left_node nod) with Node e -> e.left | _ -> raise Unproper_use_of_queue with Queue_is_empty -> nod end | _ -> raise Unproper_use_of_queue in function ( Root(min,que) ) -> try let (p, e, _) = Q.delete_min !min in (* the idea of this part is that min should never be empty, if que is not just a leaf *) match !que with Leaf _ -> (p, e, Root(min,que)) | _ -> begin if Q.is_empty !min then (* so we have an empty min with, let's rebuild *) let new_min = rebuild que in match !new_min with Leaf c -> (p, e, Root(ref c, que)) | _ -> raise Unproper_use_of_queue else (* min isn't empty *) (p, e, Root(min,que)) end with Q.Queue_is_empty -> (* if queue is really empty en exception will be raised: se fuction give_most_left_node *) let new_min = rebuild que in match !new_min with Leaf c -> delete_min ( Root(ref c, que) ) | _ -> raise Unproper_use_of_queue (* --- end of D E L E T E M I N --- *) let find_min = function ( Root(min,que) ) -> ( (function ((p, e, _ ), q) -> (p, e, q)) ((Q.find_min !min), Root(min,que)) ) let rec union q1 q2 = if is_empty q2 then q1 else ( function (p, e, q) -> union (insert q1 p e) q ) ( delete_min q2 ) end (* todo -> parameter names *)