-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHeap.pm
117 lines (83 loc) · 2.29 KB
/
Heap.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package Heap;
use strict;
use warnings;
sub new {
my ($class, $sentinel) = @_;
my $self = {
elements => [$sentinel],
};
bless $self, $class;
return $self;
}
sub retrieve {
my ($self) = @_;
return unless defined $self->{elements}->[1];
my $min_element = $self->{elements}->[1];
my $last_element = pop @{$self->{elements}};
return $min_element unless defined $self->{elements}->[1]; #no one left, no order to fix
$self->{elements}->[1] = $last_element;
$self->_move_first_down();
return $min_element;
}
sub retrieve_all {
my ($self) = @_;
return unless defined $self->{elements}->[1];
my @min_elements = ($self->retrieve());
while (defined $self->{elements}->[1] and $self->{elements}->[1] == $min_elements[0]) {
push @min_elements, $self->retrieve();
}
return @min_elements;
}
sub not_empty {
my ($self) = @_;
return defined $self->{elements}->[1];
}
sub next_element {
my ($self) = @_;
return $self->{elements}->[1];
}
sub add {
my ($self, $element) = @_;
push @{$self->{elements}}, $element;
$self->_move_last_up();
return;
}
sub _move_last_up {
my ($self) = @_;
my $current_position = $#{$self->{elements}};
my $father = int($current_position / 2);
while ($self->{elements}->[$current_position] < $self->{elements}->[$father]) {
$self->_exchange($current_position, $father);
$current_position = $father;
$father = int($father / 2);
}
return;
}
sub _move_first_down {
my ($self) = @_;
my $current_position = 1;
my $min_child_index = $self->_find_min_child($current_position);
while ((defined $min_child_index) and ($self->{elements}->[$min_child_index] < $self->{elements}->[$current_position])) {
$self->_exchange($current_position, $min_child_index);
$current_position = $min_child_index;
$min_child_index = $self->_find_min_child($current_position);
}
return;
}
sub _exchange {
my ($self, $a, $b) = @_;
($self->{elements}->[$a], $self->{elements}->[$b]) = ($self->{elements}->[$b], $self->{elements}->[$a]);
return;
}
sub _find_min_child {
my ($self, $index) = @_;
my ($child1, $child2) = (2*$index, 2*$index+1);
return unless defined $self->{elements}->[$child1];
return $child1 unless defined $self->{elements}->[$child2];
if ($self->{elements}->[$child1] < $self->{elements}->[$child2]) {
return $child1;
} else {
return $child2;
}
}
1;