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.
@@ -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[:element]
11
- comparor[:element] = element[:element]
12
- element[:element] = temp
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(node[:index])
18
- right = right(node[:index])
16
+ left = node.left
17
+ right = node.right
19
18
  largest = node
20
- if !left.nil? && left[:element] >= node[:element]
19
+ if !left.nil? && left.val >= node.val
21
20
  largest = left
22
21
  end
23
22
 
24
- if !right.nil? && right[:element] >= largest[:element]
23
+ if !right.nil? && right.val >= largest.val
25
24
  largest = right
26
25
  end
27
26
 
28
27
  if largest != node
29
- exchange(largest, node)
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
- @heap = []
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
- value = {element: element, index: size}
45
- @heap << value
46
- i = @heap.size - 1
47
- node, index = parent(i)
48
- while i != 0 && @heap[i][:element] >= node[:element] do
49
- exchange(@heap[i], node)
50
- i = index
51
- node, index = parent(i)
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
- # @return element which has maximum value in heap
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[:element]
158
+ return @root.val
59
159
  end
60
160
 
61
- # Removes the maximum value element from heap and
62
- # corrects the whole heap again
63
- # @return maximum value element
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
- maximum = root
67
- if @heap.size > 1
68
- last_value = @heap.last
69
- last_value[:index] = 0
70
- @heap = @heap.slice(0..@heap.size-2)
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
- return maximum[:element]
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[:element]
11
- comparor[:element] = element[:element]
12
- element[:element] = temp
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(node[:index])
18
- right = right(node[:index])
16
+ left = node.left
17
+ right = node.right
19
18
  smallest = node
20
- if !left.nil? && left[:element] < node[:element]
19
+ if !left.nil? && left.val < node.val
21
20
  smallest = left
22
21
  end
23
22
 
24
- if !right.nil? && right[:element] < smallest[:element]
23
+ if !right.nil? && right.val < smallest.val
25
24
  smallest = right
26
25
  end
27
26
 
28
27
  if smallest != node
29
- exchange(smallest, node)
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
- @heap = []
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
- value = {element: element, index: size}
46
- @heap << value
47
- i = size - 1
48
- node, index = parent(i)
49
- while i != 0 && @heap[i][:element] < node[:element] do
50
- exchange(@heap[i], node)
51
- i = index
52
- node, index = parent(i)
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
- # @return element which has minimum value in heap
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[:element]
158
+ return @root.val
61
159
  end
62
160
 
63
- # Removes the minimum value element from heap and
64
- # corrects the whole heap again
65
- # @return minimum value element
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
- minimum = root
69
- if @heap.size > 1
70
- last_value = @heap.last
71
- last_value[:index] = 0
72
- @heap = @heap.slice(0..@heap.size-2)
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
- return minimum[:element]
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