|
module PQ : sig |
|
type elt |
|
(** The type of elements stored in the priority queue. *) |
|
|
|
type t |
|
(** The type [t] represents a priority queue, which is used in Dijkstra's algorithm to keep track of the nodes to visit next. *) |
|
|
|
exception Queue_is_empty |
|
(** [Queue_is_empty] is raised when attempting to remove an element from an empty priority queue. *) |
|
|
|
val empty : unit -> t |
|
(** [empty ()] returns an empty priority queue. *) |
|
|
|
val insert : Node.t -> priority -> t -> t |
|
(** [insert new_node new_priority pq] returns a new priority queue [pq'] with [new_node] inserted with priority [new_priority]. *) |
|
|
|
val remove_top : t -> t |
|
(** [remove_top pq] returns a new priority queue [pq'] with the lowest priority element removed. Raises [Queue_is_empty] if [pq] is empty. *) |
|
|
|
val extract : t -> priority * Node.t * t |
|
(** [extract pq] returns a tuple of the priority, node, and priority queue of the lowest priority element in [pq]. Raises [Queue_is_empty] if [pq] is empty. *) |
|
end = struct |
|
type priority = float |
|
type elt = Empty | PQNode of priority * Node.t * elt * elt |
|
type t = { priority_queue : elt; mutex : Mutex.t } |
|
|
|
exception Queue_is_empty |
|
|
|
let empty () = { priority_queue = Empty; mutex = Mutex.create () } |
|
|
|
let insert (new_node : Node.t) (new_priority : priority) (pq : t) : t = |
|
Mutex.lock pq.mutex; |
|
let rec insert_aux new_node new_priority queue = |
|
match queue with |
|
| Empty -> PQNode (new_priority, new_node, Empty, Empty) |
|
| PQNode (existing_priority, existing_node, left, right) -> |
|
if new_priority <= existing_priority then |
|
PQNode |
|
( new_priority, |
|
new_node, |
|
insert_aux existing_node existing_priority right, |
|
left ) |
|
else |
|
PQNode |
|
( existing_priority, |
|
existing_node, |
|
insert_aux new_node new_priority right, |
|
left ) |
|
in |
|
let updated_priority_queue = |
|
insert_aux new_node new_priority pq.priority_queue |
|
in |
|
Mutex.unlock pq.mutex; |
|
{ pq with priority_queue = updated_priority_queue } |
|
|
|
let remove_top (pq : t) = |
|
let rec remove_top_aux priority_queue = |
|
match priority_queue with |
|
| Empty -> raise Queue_is_empty |
|
| PQNode (_, _, left, Empty) -> left |
|
| PQNode (_, _, Empty, right) -> right |
|
| PQNode |
|
( _, |
|
_, |
|
(PQNode (left_priority, left_node, _, _) as left), |
|
(PQNode (right_priority, right_node, _, _) as right) ) -> |
|
if left_priority <= right_priority then |
|
PQNode (left_priority, left_node, remove_top_aux left, right) |
|
else PQNode (right_priority, right_node, left, remove_top_aux right) |
|
in |
|
{ pq with priority_queue = remove_top_aux pq.priority_queue } |
|
|
|
let extract (pq : t) = |
|
Mutex.lock pq.mutex; |
|
let extract_aux priority_queue = |
|
match priority_queue with |
|
| Empty -> raise Queue_is_empty |
|
| PQNode (priority, elt, _, _) as queue -> |
|
(priority, elt, remove_top { pq with priority_queue = queue }) |
|
in |
|
let priority, extracted_node, updated_pq = extract_aux pq.priority_queue in |
|
Mutex.unlock pq.mutex; |
|
(priority, extracted_node, updated_pq) |
|
end |