collection_utils 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.coveralls.yml +1 -0
- data/Gemfile +3 -0
- data/README.md +1 -1
- data/lib/collection_utils.rb +1 -1
- data/lib/collection_utils/hash_deserialized_object.rb +114 -0
- data/lib/collection_utils/heap.rb +190 -109
- data/lib/collection_utils/heap_utils/max_heap.rb +165 -33
- data/lib/collection_utils/heap_utils/min_heap.rb +165 -35
- data/lib/collection_utils/queue.rb +23 -3
- data/lib/collection_utils/set.rb +144 -0
- data/lib/collection_utils/stack.rb +8 -2
- data/lib/collection_utils/tree_utils/bst.rb +194 -38
- data/lib/collection_utils/version.rb +1 -1
- metadata +5 -2
|
@@ -4,78 +4,210 @@ module CollectionUtils
|
|
|
4
4
|
class MaxHeap < CollectionUtils::Heap
|
|
5
5
|
|
|
6
6
|
private
|
|
7
|
-
attr_accessor :heap
|
|
8
7
|
|
|
9
8
|
def exchange(element, comparor)
|
|
10
|
-
temp = comparor
|
|
11
|
-
comparor
|
|
12
|
-
element
|
|
9
|
+
temp = comparor.val
|
|
10
|
+
comparor.val = element.val
|
|
11
|
+
element.val = temp
|
|
13
12
|
return element, comparor
|
|
14
13
|
end
|
|
15
14
|
|
|
16
15
|
def heapify(node)
|
|
17
|
-
left = left
|
|
18
|
-
right = right
|
|
16
|
+
left = node.left
|
|
17
|
+
right = node.right
|
|
19
18
|
largest = node
|
|
20
|
-
if !left.nil? && left
|
|
19
|
+
if !left.nil? && left.val >= node.val
|
|
21
20
|
largest = left
|
|
22
21
|
end
|
|
23
22
|
|
|
24
|
-
if !right.nil? && right
|
|
23
|
+
if !right.nil? && right.val >= largest.val
|
|
25
24
|
largest = right
|
|
26
25
|
end
|
|
27
26
|
|
|
28
27
|
if largest != node
|
|
29
|
-
|
|
28
|
+
@incomplete_set.delete(largest)
|
|
29
|
+
@incomplete_set.delete(node)
|
|
30
|
+
@leaf_set.delete(largest)
|
|
31
|
+
@leaf_set.delete(node)
|
|
32
|
+
largest, node = exchange(largest, node)
|
|
33
|
+
@incomplete_set.insert(largest) if largest.is_incomplete?
|
|
34
|
+
@leaf_set.insert(largest) if largest.is_leaf?
|
|
35
|
+
@incomplete_set.insert(node) if node.is_incomplete?
|
|
36
|
+
@leaf_set.insert(node) if node.is_leaf?
|
|
30
37
|
heapify(largest)
|
|
31
38
|
end
|
|
39
|
+
end
|
|
32
40
|
|
|
41
|
+
def bubble_up(node)
|
|
42
|
+
parent = node.parent
|
|
43
|
+
actual_node = node
|
|
44
|
+
while !parent.nil? do
|
|
45
|
+
@incomplete_set.delete(parent)
|
|
46
|
+
@incomplete_set.delete(actual_node)
|
|
47
|
+
@leaf_set.delete(parent)
|
|
48
|
+
@leaf_set.delete(actual_node)
|
|
49
|
+
if parent.val < actual_node.val
|
|
50
|
+
parent, actual_node = exchange(parent, actual_node)
|
|
51
|
+
@incomplete_set.insert(parent) if parent.is_incomplete?
|
|
52
|
+
@leaf_set.insert(parent) if parent.is_leaf?
|
|
53
|
+
@incomplete_set.insert(actual_node) if actual_node.is_incomplete?
|
|
54
|
+
@leaf_set.insert(actual_node) if actual_node.is_leaf?
|
|
55
|
+
actual_node = parent
|
|
56
|
+
parent = actual_node.parent
|
|
57
|
+
else
|
|
58
|
+
@incomplete_set.insert(parent) if parent.is_incomplete?
|
|
59
|
+
@leaf_set.insert(parent) if parent.is_leaf?
|
|
60
|
+
@incomplete_set.insert(actual_node) if actual_node.is_incomplete?
|
|
61
|
+
@leaf_set.insert(actual_node) if actual_node.is_leaf?
|
|
62
|
+
break
|
|
63
|
+
end
|
|
64
|
+
end
|
|
33
65
|
end
|
|
34
66
|
|
|
35
67
|
public
|
|
36
68
|
def initialize(array = [])
|
|
37
|
-
@
|
|
69
|
+
@size = 0
|
|
70
|
+
@root = nil
|
|
71
|
+
@incomplete_set = CollectionUtils::Set.new()
|
|
72
|
+
@leaf_set = CollectionUtils::Set.new()
|
|
38
73
|
array.each_with_index do |element, index|
|
|
39
74
|
insert(element)
|
|
40
75
|
end
|
|
41
76
|
end
|
|
42
77
|
|
|
78
|
+
# Removes the maximum value element from heap and
|
|
79
|
+
# corrects the whole heap again. This is done in O(logn) operations as
|
|
80
|
+
# correction of tree takes logn time
|
|
81
|
+
# @return maximum value
|
|
82
|
+
# @example Max heap should return maximum value
|
|
83
|
+
# => @heap = CollectionUtils::HeapUtils::MaxHeap.new([5,2,3,4])
|
|
84
|
+
# => # Min Heap would look like this
|
|
85
|
+
# => # 5
|
|
86
|
+
# => # / \
|
|
87
|
+
# => # 4 3
|
|
88
|
+
# => # /
|
|
89
|
+
# => # 2
|
|
90
|
+
# => @heap.insert(6)
|
|
91
|
+
# => # 6
|
|
92
|
+
# => # / \
|
|
93
|
+
# => # 5 3
|
|
94
|
+
# => # / \
|
|
95
|
+
# => # 2 4
|
|
43
96
|
def insert(element)
|
|
44
|
-
|
|
45
|
-
@
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
97
|
+
node = Node.new(element)
|
|
98
|
+
@size += 1
|
|
99
|
+
if @root.nil?
|
|
100
|
+
@root = node
|
|
101
|
+
@root.level = 1
|
|
102
|
+
@level = 1
|
|
103
|
+
@leaf_set.insert(node)
|
|
104
|
+
return
|
|
105
|
+
end
|
|
106
|
+
unless @incomplete_set.is_empty?
|
|
107
|
+
parent_node = @incomplete_set.get
|
|
108
|
+
@incomplete_set.delete(parent_node)
|
|
109
|
+
if parent_node.left.nil?
|
|
110
|
+
node.parent = parent_node
|
|
111
|
+
node.level = parent_node.level + 1
|
|
112
|
+
parent_node.left = node
|
|
113
|
+
@level = node.level if node.level > @level
|
|
114
|
+
bubble_up(node)
|
|
115
|
+
return
|
|
116
|
+
end
|
|
117
|
+
if parent_node.right.nil?
|
|
118
|
+
node.parent = parent_node
|
|
119
|
+
node.level = parent_node.level + 1
|
|
120
|
+
parent_node.right = node
|
|
121
|
+
@level = node.level if node.level > @level
|
|
122
|
+
bubble_up(node)
|
|
123
|
+
return
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
unless @leaf_set.is_empty?
|
|
128
|
+
parent_node = @leaf_set.get
|
|
129
|
+
@leaf_set.delete(parent_node)
|
|
130
|
+
node.parent = parent_node
|
|
131
|
+
node.level = parent_node.level + 1
|
|
132
|
+
parent_node.left = node
|
|
133
|
+
@level = node.level if node.level > @level
|
|
134
|
+
bubble_up(node)
|
|
135
|
+
return
|
|
52
136
|
end
|
|
53
137
|
end
|
|
54
138
|
|
|
55
|
-
#
|
|
139
|
+
# This will insert the value in max heap. This takes O(1) operations
|
|
140
|
+
# @return maximum value
|
|
141
|
+
# @example Max heap remove maximum value and return it
|
|
142
|
+
# => @heap = CollectionUtils::HeapUtils::MaxHeap.new([5,2,3,4])
|
|
143
|
+
# => # Max Heap would look like this
|
|
144
|
+
# => # 5
|
|
145
|
+
# => # / \
|
|
146
|
+
# => # 4 3
|
|
147
|
+
# => # /
|
|
148
|
+
# => # 2
|
|
149
|
+
# => value = @heap.get_max
|
|
150
|
+
# => # 5
|
|
151
|
+
# => # / \
|
|
152
|
+
# => # 4 3
|
|
153
|
+
# => # /
|
|
154
|
+
# => # 2
|
|
155
|
+
# => # value = 5
|
|
56
156
|
def get_max
|
|
57
157
|
return if is_empty?
|
|
58
|
-
return root
|
|
158
|
+
return @root.val
|
|
59
159
|
end
|
|
60
160
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
161
|
+
# This will insert the value in max heap. This takes O(logn) operations
|
|
162
|
+
# as adding the element will trigger the correction of the tree
|
|
163
|
+
# @return maximum value
|
|
164
|
+
# @example Max heap remove maximum value and return it
|
|
165
|
+
# => @heap = CollectionUtils::HeapUtils::MaxHeap.new([5,2,3,4])
|
|
166
|
+
# => # Max Heap would look like this
|
|
167
|
+
# => # 5
|
|
168
|
+
# => # / \
|
|
169
|
+
# => # 4 3
|
|
170
|
+
# => # /
|
|
171
|
+
# => # 2
|
|
172
|
+
# => value = @heap.extract_max
|
|
173
|
+
# => # 4
|
|
174
|
+
# => # / \
|
|
175
|
+
# => # 2 3
|
|
176
|
+
# => #
|
|
177
|
+
# => # value = 5
|
|
64
178
|
def extract_max
|
|
65
179
|
return if is_empty?
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
@heap[0] = last_value
|
|
72
|
-
heapify(root)
|
|
73
|
-
else
|
|
74
|
-
@heap =[ ]
|
|
180
|
+
if size == 1
|
|
181
|
+
@size = 0
|
|
182
|
+
value = @root.val
|
|
183
|
+
@root = nil
|
|
184
|
+
return value
|
|
75
185
|
end
|
|
186
|
+
maximum = @root.val
|
|
187
|
+
@size -= 1
|
|
188
|
+
node = @leaf_set.get
|
|
189
|
+
replaced_value = node.val
|
|
190
|
+
@leaf_set.delete(node)
|
|
191
|
+
@incomplete_set.delete(node)
|
|
192
|
+
parent = node.parent
|
|
193
|
+
parent.left == node ? parent.left = nil : parent.right = nil
|
|
194
|
+
@leaf_set.delete(parent)
|
|
195
|
+
@incomplete_set.delete(parent)
|
|
196
|
+
node = nil
|
|
197
|
+
@incomplete_set.insert(parent) if parent.is_incomplete?
|
|
198
|
+
@leaf_set.insert(parent) if parent.is_leaf?
|
|
76
199
|
|
|
77
|
-
|
|
200
|
+
@leaf_set.delete(@root)
|
|
201
|
+
@incomplete_set.delete(@root)
|
|
202
|
+
@root.val = replaced_value
|
|
203
|
+
@incomplete_set.insert(@root) if @root.is_incomplete?
|
|
204
|
+
@leaf_set.insert(@root) if @root.is_leaf?
|
|
205
|
+
heapify(@root)
|
|
206
|
+
return maximum
|
|
78
207
|
end
|
|
208
|
+
|
|
209
|
+
alias :delete :extract_max
|
|
210
|
+
|
|
79
211
|
end
|
|
80
212
|
end
|
|
81
213
|
end
|
|
@@ -4,80 +4,210 @@ module CollectionUtils
|
|
|
4
4
|
class MinHeap < CollectionUtils::Heap
|
|
5
5
|
|
|
6
6
|
private
|
|
7
|
-
attr_accessor :heap
|
|
8
7
|
|
|
9
8
|
def exchange(element, comparor)
|
|
10
|
-
temp = comparor
|
|
11
|
-
comparor
|
|
12
|
-
element
|
|
9
|
+
temp = comparor.val
|
|
10
|
+
comparor.val = element.val
|
|
11
|
+
element.val = temp
|
|
13
12
|
return element, comparor
|
|
14
13
|
end
|
|
15
14
|
|
|
16
15
|
def heapify(node)
|
|
17
|
-
left = left
|
|
18
|
-
right = right
|
|
16
|
+
left = node.left
|
|
17
|
+
right = node.right
|
|
19
18
|
smallest = node
|
|
20
|
-
if !left.nil? && left
|
|
19
|
+
if !left.nil? && left.val < node.val
|
|
21
20
|
smallest = left
|
|
22
21
|
end
|
|
23
22
|
|
|
24
|
-
if !right.nil? && right
|
|
23
|
+
if !right.nil? && right.val < smallest.val
|
|
25
24
|
smallest = right
|
|
26
25
|
end
|
|
27
26
|
|
|
28
27
|
if smallest != node
|
|
29
|
-
|
|
28
|
+
@incomplete_set.delete(smallest)
|
|
29
|
+
@incomplete_set.delete(node)
|
|
30
|
+
@leaf_set.delete(smallest)
|
|
31
|
+
@leaf_set.delete(node)
|
|
32
|
+
smallest, node = exchange(smallest, node)
|
|
33
|
+
@incomplete_set.insert(smallest) if smallest.is_incomplete?
|
|
34
|
+
@leaf_set.insert(smallest) if smallest.is_leaf?
|
|
35
|
+
@incomplete_set.insert(node) if node.is_incomplete?
|
|
36
|
+
@leaf_set.insert(node) if node.is_leaf?
|
|
30
37
|
heapify(smallest)
|
|
31
38
|
end
|
|
32
|
-
|
|
33
39
|
end
|
|
34
40
|
|
|
41
|
+
def bubble_up(node)
|
|
42
|
+
parent = node.parent
|
|
43
|
+
actual_node = node
|
|
44
|
+
while !parent.nil? do
|
|
45
|
+
@incomplete_set.delete(parent)
|
|
46
|
+
@incomplete_set.delete(actual_node)
|
|
47
|
+
@leaf_set.delete(parent)
|
|
48
|
+
@leaf_set.delete(actual_node)
|
|
49
|
+
if parent.val >= actual_node.val
|
|
50
|
+
parent, actual_node = exchange(parent, actual_node)
|
|
51
|
+
@incomplete_set.insert(parent) if parent.is_incomplete?
|
|
52
|
+
@leaf_set.insert(parent) if parent.is_leaf?
|
|
53
|
+
@incomplete_set.insert(actual_node) if actual_node.is_incomplete?
|
|
54
|
+
@leaf_set.insert(actual_node) if actual_node.is_leaf?
|
|
55
|
+
actual_node = parent
|
|
56
|
+
parent = actual_node.parent
|
|
57
|
+
else
|
|
58
|
+
@incomplete_set.insert(parent) if parent.is_incomplete?
|
|
59
|
+
@leaf_set.insert(parent) if parent.is_leaf?
|
|
60
|
+
@incomplete_set.insert(actual_node) if actual_node.is_incomplete?
|
|
61
|
+
@leaf_set.insert(actual_node) if actual_node.is_leaf?
|
|
62
|
+
break
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
35
66
|
|
|
36
67
|
public
|
|
37
68
|
def initialize(array = [])
|
|
38
|
-
@
|
|
69
|
+
@size = 0
|
|
70
|
+
@root = nil
|
|
71
|
+
@incomplete_set = CollectionUtils::Set.new()
|
|
72
|
+
@leaf_set = CollectionUtils::Set.new()
|
|
39
73
|
array.each_with_index do |element, index|
|
|
40
74
|
insert(element)
|
|
41
75
|
end
|
|
42
76
|
end
|
|
43
77
|
|
|
78
|
+
# This will insert the value in min heap. This takes O(logn) operations
|
|
79
|
+
# as adding the element will trigger the correction of the tree
|
|
80
|
+
# @param element which needs to be added into the min heap
|
|
81
|
+
# @example Min heap should add another element
|
|
82
|
+
# => @heap = CollectionUtils::HeapUtils::MinHeap.new([5,2,3,4])
|
|
83
|
+
# => # Min Heap would look like this
|
|
84
|
+
# => # 2
|
|
85
|
+
# => # / \
|
|
86
|
+
# => # 5 3
|
|
87
|
+
# => # /
|
|
88
|
+
# => # 4
|
|
89
|
+
# => @heap.insert(1)
|
|
90
|
+
# => # 1
|
|
91
|
+
# => # / \
|
|
92
|
+
# => # 2 3
|
|
93
|
+
# => # / \
|
|
94
|
+
# => # 4 5
|
|
44
95
|
def insert(element)
|
|
45
|
-
|
|
46
|
-
@
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
96
|
+
node = Node.new(element)
|
|
97
|
+
@size += 1
|
|
98
|
+
if @root.nil?
|
|
99
|
+
@root = node
|
|
100
|
+
@root.level = 1
|
|
101
|
+
@level = 1
|
|
102
|
+
@leaf_set.insert(node)
|
|
103
|
+
return
|
|
104
|
+
end
|
|
105
|
+
unless @incomplete_set.is_empty?
|
|
106
|
+
parent_node = @incomplete_set.get
|
|
107
|
+
@incomplete_set.delete(parent_node)
|
|
108
|
+
if parent_node.left.nil?
|
|
109
|
+
node.parent = parent_node
|
|
110
|
+
node.level = parent_node.level + 1
|
|
111
|
+
parent_node.left = node
|
|
112
|
+
@level = node.level if node.level > @level
|
|
113
|
+
bubble_up(node)
|
|
114
|
+
return
|
|
115
|
+
end
|
|
116
|
+
if parent_node.right.nil?
|
|
117
|
+
node.parent = parent_node
|
|
118
|
+
node.level = parent_node.level + 1
|
|
119
|
+
parent_node.right = node
|
|
120
|
+
@level = node.level if node.level > @level
|
|
121
|
+
bubble_up(node)
|
|
122
|
+
return
|
|
123
|
+
end
|
|
53
124
|
end
|
|
54
|
-
end
|
|
55
125
|
|
|
126
|
+
unless @leaf_set.is_empty?
|
|
127
|
+
parent_node = @leaf_set.get
|
|
128
|
+
@leaf_set.delete(parent_node)
|
|
129
|
+
node.parent = parent_node
|
|
130
|
+
node.level = parent_node.level + 1
|
|
131
|
+
parent_node.left = node
|
|
132
|
+
@level = node.level if node.level > @level
|
|
133
|
+
bubble_up(node)
|
|
134
|
+
return
|
|
135
|
+
end
|
|
136
|
+
end
|
|
56
137
|
|
|
57
|
-
#
|
|
138
|
+
# Returns the minimum value element from heap and
|
|
139
|
+
# This is done in O(1) operations.
|
|
140
|
+
# @return minimum value
|
|
141
|
+
# @example Min heap should return minimum value
|
|
142
|
+
# => @heap = CollectionUtils::HeapUtils::MinHeap.new([5,2,3,4])
|
|
143
|
+
# => # Min Heap would look like this
|
|
144
|
+
# => # 2
|
|
145
|
+
# => # / \
|
|
146
|
+
# => # 5 3
|
|
147
|
+
# => # /
|
|
148
|
+
# => # 4
|
|
149
|
+
# => value = @heap.get_min
|
|
150
|
+
# => # 2
|
|
151
|
+
# => # / \
|
|
152
|
+
# => # 5 3
|
|
153
|
+
# => # /
|
|
154
|
+
# => # 4
|
|
155
|
+
# => # value = 2
|
|
58
156
|
def get_min
|
|
59
157
|
return if is_empty?
|
|
60
|
-
return root
|
|
158
|
+
return @root.val
|
|
61
159
|
end
|
|
62
160
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
161
|
+
# Removes the minimum value element from heap and
|
|
162
|
+
# corrects the whole heap again. This is done in O(logn) operations as
|
|
163
|
+
# correction of tree takes logn time
|
|
164
|
+
# @return minimum value
|
|
165
|
+
# @example Min heap should return minimum value
|
|
166
|
+
# => @heap = CollectionUtils::HeapUtils::MinHeap.new([5,2,3,4])
|
|
167
|
+
# => # Min Heap would look like this
|
|
168
|
+
# => # 2
|
|
169
|
+
# => # / \
|
|
170
|
+
# => # 5 3
|
|
171
|
+
# => # /
|
|
172
|
+
# => # 4
|
|
173
|
+
# => value = @heap.extract_min
|
|
174
|
+
# => # 3
|
|
175
|
+
# => # / \
|
|
176
|
+
# => # 5 4
|
|
177
|
+
# => # value = 2
|
|
66
178
|
def extract_min
|
|
67
179
|
return if is_empty?
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
@heap[0] = last_value
|
|
74
|
-
heapify(root)
|
|
75
|
-
else
|
|
76
|
-
@heap =[]
|
|
180
|
+
if size == 1
|
|
181
|
+
@size = 0
|
|
182
|
+
value = @root.val
|
|
183
|
+
@root = nil
|
|
184
|
+
return value
|
|
77
185
|
end
|
|
186
|
+
minimum = @root.val
|
|
187
|
+
@size -= 1
|
|
188
|
+
node = @leaf_set.get
|
|
189
|
+
replaced_value = node.val
|
|
190
|
+
@leaf_set.delete(node)
|
|
191
|
+
@incomplete_set.delete(node)
|
|
192
|
+
parent = node.parent
|
|
193
|
+
parent.left == node ? parent.left = nil : parent.right = nil
|
|
194
|
+
@leaf_set.delete(parent)
|
|
195
|
+
@incomplete_set.delete(parent)
|
|
196
|
+
node = nil
|
|
197
|
+
@incomplete_set.insert(parent) if parent.is_incomplete?
|
|
198
|
+
@leaf_set.insert(parent) if parent.is_leaf?
|
|
78
199
|
|
|
79
|
-
|
|
200
|
+
@leaf_set.delete(@root)
|
|
201
|
+
@incomplete_set.delete(@root)
|
|
202
|
+
@root.val = replaced_value
|
|
203
|
+
@incomplete_set.insert(@root) if @root.is_incomplete?
|
|
204
|
+
@leaf_set.insert(@root) if @root.is_leaf?
|
|
205
|
+
heapify(@root)
|
|
206
|
+
return minimum
|
|
80
207
|
end
|
|
208
|
+
|
|
209
|
+
alias :delete :extract_min
|
|
210
|
+
|
|
81
211
|
end
|
|
82
212
|
end
|
|
83
213
|
end
|