(Ord: OrderedType) = struct
type data = Ord.t
type heap = {
mutable hp_heap: data array;
mutable hp_length: int;
hp_null_element: data;
}
type t = heap
let compare_min =
Ord.compare
let compare_max x y =
Ord.compare y x
let create (null_element: data) : heap = {
hp_heap = [| |];
hp_length = 0;
hp_null_element = null_element;
}
let to_string (heap: heap) : string =
let rec to_string' i =
if i >= heap.hp_length then
""
else
string_of_int i ^ ": " ^ Ord.to_string heap.hp_heap.(i) ^ "\n" ^ to_string' (i + 1)
in
to_string' 0
let is_min_level (index: int) : bool =
let level =
log (float_of_int (index + 1)) /. log (float_of_int 2)
in
((int_of_float level) mod 2) = 0
let left_child_index (index: int) : int =
index * 2 + 1
let right_child_index (index: int) : int =
index * 2 + 2
let parent_index (index: int) : int =
(index - 1) / 2
let within_bound (heap: heap) (index: int) : bool =
index < heap.hp_length
let min_entry (compare: data -> data -> int) (heap: heap) (first_index: int) (second_index: int) : int =
if compare heap.hp_heap.(first_index) heap.hp_heap.(second_index) <= 0 then
first_index
else
second_index
let min_with_descendants (compare: data -> data -> int) (heap: heap) (index: int) : int =
let left_child =
left_child_index index
in
if within_bound heap left_child then begin
let right_child =
right_child_index index
in
if within_bound heap right_child then
min_entry compare heap index (min_entry compare heap left_child right_child)
else
min_entry compare heap index left_child
end
else
index
let increase_heap_size (heap: heap) (data: data) : unit =
if heap.hp_length >= Array.length heap.hp_heap then begin
if heap.hp_length = Sys.max_array_length then begin
raise OVERFLOW;
end;
let new_size =
let desired_size =
Tools.max_int 256 (2 * (Array.length heap.hp_heap))
in
Pervasives.min Sys.max_array_length desired_size
in
let new_heap =
Array.make new_size data
in
Array.blit heap.hp_heap 0 new_heap 0 (Array.length heap.hp_heap);
heap.hp_heap <- new_heap;
end
let rec sift_up' (compare: data -> data -> int) (heap: heap) (data: data) (index: int) : unit =
if index > 2 then begin
let grand_parent : int =
parent_index (parent_index index)
in
if compare data heap.hp_heap.(grand_parent) < 0 then begin
heap.hp_heap.(index) <- heap.hp_heap.(grand_parent);
sift_up' compare heap data grand_parent
end
else
heap.hp_heap.(index) <- data;
end
else begin
heap.hp_heap.(index) <- data;
end
let rec sift_up (heap: heap) (data: data) (index: int) : unit =
if is_min_level index then begin
let parent =
parent_index index
in
if Ord.compare data heap.hp_heap.(parent) > 0 then begin
heap.hp_heap.(index) <- heap.hp_heap.(parent);
sift_up' compare_max heap data parent
end
else begin
sift_up' compare_min heap data index
end
end
else begin
let parent =
parent_index index
in
if Ord.compare data heap.hp_heap.(parent) < 0 then begin
heap.hp_heap.(index) <- heap.hp_heap.(parent);
sift_up' compare_min heap data parent
end
else begin
sift_up' compare_max heap data index
end
end
let add' (heap: heap) (data: data) : unit =
increase_heap_size heap data;
if heap.hp_length = 0 then
heap.hp_heap.(0) <- data
else
sift_up heap data heap.hp_length;
heap.hp_length <- heap.hp_length + 1
let rec sift_down (compare: data -> data -> int) (heap: heap) (data: data) (index: int) : unit =
let left_child =
left_child_index index
in
if within_bound heap left_child then begin
let min_left_index =
min_with_descendants compare heap left_child
in
let right_child =
right_child_index index
in
let min_children_index =
if within_bound heap right_child then begin
min_entry compare heap min_left_index (min_with_descendants compare heap right_child)
end
else
min_left_index
in
if compare data heap.hp_heap.(min_children_index) <= 0 then begin
heap.hp_heap.(index) <- data;
end
else if
min_children_index = left_child
||
min_children_index = right_child
then begin
heap.hp_heap.(index) <- heap.hp_heap.(min_children_index);
heap.hp_heap.(min_children_index) <- data;
end
else begin
heap.hp_heap.(index) <- heap.hp_heap.(min_children_index);
let parent_index =
parent_index min_children_index
in
if compare data heap.hp_heap.(parent_index) > 0 then begin
let new_data =
heap.hp_heap.(parent_index)
in
heap.hp_heap.(parent_index) <- data;
sift_down compare heap new_data min_children_index
end
else begin
sift_down compare heap data min_children_index
end
end
end
else begin
heap.hp_heap.(index) <- data;
end
let min (heap: heap) : data =
if heap.hp_length <= 0 then begin
raise Not_found
end;
heap.hp_heap.(0)
let remove_min' (heap: heap) : data =
let data =
min heap
in
heap.hp_length <- heap.hp_length - 1;
if heap.hp_length > 0 then begin
sift_down compare_min heap heap.hp_heap.(heap.hp_length) 0
end;
heap.hp_heap.(heap.hp_length) <- heap.hp_null_element;
data
let max_index (heap: heap) : int =
if heap.hp_length <= 0 then
raise Not_found
else if heap.hp_length = 1 then
0
else if heap.hp_length = 2 then
1
else if Ord.compare heap.hp_heap.(1) heap.hp_heap.(2) > 0 then
1
else
2
let max (heap: heap) : data =
heap.hp_heap.(max_index heap)
let remove_max' (heap: heap) : data =
let index =
max_index heap
in
let data =
heap.hp_heap.(index)
in
heap.hp_length <- heap.hp_length - 1;
if heap.hp_length > 1 then begin
sift_down compare_max heap heap.hp_heap.(heap.hp_length) index
end;
heap.hp_heap.(heap.hp_length) <- heap.hp_null_element;
data
let check (heap : heap) : unit =
if Const.debug then begin
for i = 0 to heap.hp_length - 1 do
if heap.hp_heap.(i) == heap.hp_null_element then
failwith "Min_max_heap.check: null_element"
done;
for i = 0 to heap.hp_length - 1 do
let check_at index =
if is_min_level i then begin
if
within_bound heap index
&&
Ord.compare heap.hp_heap.(i) heap.hp_heap.(index) > 0
then
failwith "Min_max_heap.check: min_level"
end
else begin
if
within_bound heap index
&&
Ord.compare heap.hp_heap.(i) heap.hp_heap.(index) < 0
then
failwith ("Min_max_heap.check: max_level " ^ string_of_int i ^ " <-> " ^ string_of_int index);
end
in
check_at (left_child_index i);
check_at (left_child_index (left_child_index i));
check_at (right_child_index (left_child_index i));
check_at (right_child_index i);
check_at (left_child_index (right_child_index i));
check_at (right_child_index (right_child_index i));
done;
begin
let heap' = { heap with
hp_heap = Array.copy heap.hp_heap
}
in
let last_min =
ref None
in
while heap'.hp_length > 0 do
let min =
remove_min' heap'
in
begin
match !last_min with
| None ->
()
| Some last ->
if Ord.compare last min >= 0 then begin
print_endline ("PREV: " ^ Ord.to_string last);
failwith "Heap.check' min";
end
end;
last_min := Some min
done
end;
begin
let heap' = { heap with
hp_heap = Array.copy heap.hp_heap
}
in
let last_max =
ref None
in
while heap'.hp_length > 0 do
let max =
remove_max' heap'
in
begin
match !last_max with
| None ->
()
| Some last ->
if Ord.compare last max <= 0 then begin
print_endline ("PREV: " ^ Ord.to_string last);
failwith "Heap.check' max";
end
end;
last_max := Some max
done
end;
end
let add (heap: heap) (data: data) : unit =
add' heap data;
check heap
let remove_min (heap: heap) : data =
let min =
remove_min' heap
in
check heap;
min
let remove_max (heap: heap) : data =
let max =
remove_max' heap
in
check heap;
max
let iter (func: data -> unit) (heap: heap) : unit =
for i = 0 to heap.hp_length - 1 do
func heap.hp_heap.(i)
done
let is_empty (heap: heap) : bool =
heap.hp_length = 0
let size (heap: heap) : int =
heap.hp_length
end