algorithmix 0.0.0.4 → 0.0.0.4.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ac9e4d6a402a8e5a2114525fc9309e68f64e44b2
4
- data.tar.gz: 3f04fc2ca5c59e1b3287372e629bda85319cbf1f
3
+ metadata.gz: 7d842f0aaccbd42b0b889d9eb1f3e8c7dac5d84a
4
+ data.tar.gz: 7908a79a6005b07d6aa97f50ece276b0d4a33650
5
5
  SHA512:
6
- metadata.gz: 4b6271b398a3905cbcf52dc50800d3098362de2fd28b3ffffd882576487549d38efb7be18b85d56335567597aa89e5250937c4d063bcc5297246739586cfa30c
7
- data.tar.gz: 28d57ee9d13a571051cc00e0858c7d97dee1a3f307f03d541d88c507973f966495611449986a35aee4d593a0da92d30cdb5f4e1293e8cb8615dfa6134ffa5d05
6
+ metadata.gz: d3ce32ef804f089f1db22aed4749e953fa643156dd8d482af0dffd9670bf74aa3fa066a0b36862d12ea69c0849e0d30e3501051ff6e25c94cb9f74f0d6cefec8
7
+ data.tar.gz: 66983d3763e7d7b29c0562b7a2ad6df3289c0664b769d13e21013443dfc26ea3ab8589f091d2e77733bfffa5e048886aa529d6d5ad01cfc98bb28c7e41b45b80
@@ -10,11 +10,11 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["*@*.*"]
11
11
  spec.summary = %q{The gem contains various implementations of known and uknown data structures and algorithms}
12
12
  spec.description = <<-DOC
13
- Currently the gem contains:
14
- 1. Stack
15
- 2. Queue
16
- 3. Deque
17
- 4. Binary heap
13
+ Currently the gem contains:\n
14
+ 1. Stack\n
15
+ 2. Queue\n
16
+ 3. Deque\n
17
+ 4. Binary heap\n
18
18
 
19
19
  DOC
20
20
  spec.homepage = "https://github.com/monzita/algorithmix/wiki"
@@ -0,0 +1,452 @@
1
+ # Documentation: https://github.com/monzita/algorithmix/wiki/BinaryHeap
2
+
3
+ module Algorithmix
4
+ module DataStructure
5
+ module Heap
6
+
7
+ class BinaryHeap
8
+
9
+ # Creates a new binary heap.
10
+ #
11
+ # @param obj [#to_a] can be any object, which responds to #to_a method. By default is set to nil.
12
+ # @kwarg copy [true, false] if is set to true, content of the object will be copied into content of the new heap.
13
+ # By default is set to false.
14
+ # @kwarg min [true, false] defines the type of the new heap, be default min is set to false
15
+ # @raise ArgumentError, if given object doesn't respond to #to_a method.
16
+ # @return [BinaryHeap] a newly created binary heap
17
+ def initialize(obj = nil, copy: false, min: false)
18
+ @container = []
19
+ @max = min ? false : true
20
+ obj.nil? ? nil : from_obj(obj, copy)
21
+ end
22
+
23
+ # Assigns content of an object, to content of the heap.
24
+ #
25
+ # @param obj [#to_a] can be any object, which responds to #to_a method. By default is set to nil.
26
+ # @kwarg copy [true, false] if is set to true, content of the object will be copied into content of the new heap.
27
+ # By default is set to false.
28
+ # @raise ArgumentError, if given object doesn't respond to #to_a method.
29
+ # @return [BinaryHeap] self object
30
+ def assign(obj, copy: false)
31
+ from_obj(obj, copy)
32
+ end
33
+
34
+ # Inserts a value in the heap.
35
+ #
36
+ # @param value
37
+ # @return [BinaryHeap] self object
38
+ def insert(value)
39
+ @container << value
40
+ sift_up(@container.size - 1)
41
+ self
42
+ end
43
+
44
+ # (see #insert)
45
+ def <<(value)
46
+ insert(value)
47
+ end
48
+
49
+ # Removes top element of the heap.
50
+ #
51
+ # @raise Algorithmix::EmptyContainerError, if the heap is empty.
52
+ # @return top element of the heap.
53
+ def extract
54
+ raise EmptyContainerError, "The Binary heap is empty." if @container.empty?
55
+ @container[0], @container[@container.length - 1] = @container[@container.length - 1], @container[0]
56
+ value = @container.pop
57
+ heapify(0)
58
+ value
59
+ end
60
+
61
+ # Returns top element of the heap, without removing it.
62
+ #
63
+ # @return top element.
64
+ def top
65
+ @container.first
66
+ end
67
+
68
+ # Returns number of elements in the heap.
69
+ def size
70
+ @container.size
71
+ end
72
+
73
+ # Returns information for current ...
74
+ def empty?
75
+ @container.empty?
76
+ end
77
+
78
+ # Increases a value in the heap, if current heap is set to be max heap.
79
+ #
80
+ # @kwarg idx [Integer] any integer, which can represent index at an array.
81
+ # @krarg old_value
82
+ # @kwarg new_value
83
+ # @raise TypeError, if current heap has type min heap
84
+ # @raise ArgumentError, if idx or old_value are not provided
85
+ # @raise ArgumentError, if new_value is not provided
86
+ # @return [BinaryHeap] self object
87
+ def increase_key(idx: nil, old_value: nil, new_value: nil)
88
+ raise TypeError, "Undefined method BinaryHeap#increase_key for MinBinaryHeap" if !@max
89
+ raise ArgumentError, "At least one of both options must be provided." if idx.nil? && old_value.nil?
90
+ raise ArgumentError, ":new_value cannot be nil." if new_value.nil?
91
+
92
+ idx = idx.nil? && !old_value.nil? ? @container.index(old_value) : idx
93
+ raise ArgumentError, "Element at position #{idx} doesn't exist." if idx.nil? || @container[idx].nil?
94
+ change_key(idx, new_value, increase: true)
95
+
96
+ self
97
+ end
98
+
99
+
100
+ # Decreases a value in the heap, if current heap is set to be min heap.
101
+ #
102
+ # @kwarg idx [Integer] any integer, which can represent index at an array.
103
+ # @krarg old_value
104
+ # @kwarg new_value
105
+ # @raise TypeError, if current heap has type max heap
106
+ # @raise ArgumentError, if idx or old_value are not provided
107
+ # @raise ArgumentError, if new_value is not provided
108
+ # @return [BinaryHeap] self object
109
+ def decrease_key(idx: nil, old_value: nil, new_value: nil)
110
+ raise TypeError, "Undefined method BinaryHeap#decrease_key for MaxBinaryHeap" if @max
111
+ raise ArgumentError, "At least one of both options must be provided." if idx.nil? && old_value.nil?
112
+ raise ArgumentError, ":new_value cannot be nil." if new_value.nil?
113
+
114
+ idx = idx.nil? && !old_value.nil? ? @container.index(old_value) : idx
115
+ raise ArgumentError, "Element at position #{idx} doesn't exist." if idx.nil? || @container[idx].nil?
116
+ change_key(idx, new_value)
117
+
118
+ self
119
+ end
120
+
121
+ # Compares contents of the heap, and a heap given as argument.
122
+ #
123
+ # @param binary_heap [BinaryHeap]
124
+ # @raise ArgumentError, if given object is not a heap.
125
+ # @return [true, false] true if heaps are equal, false otherwise
126
+ def ==(binary_heap)
127
+ raise ArgumentError, "Undefined method BinaryHeap#== for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
128
+ @container == binary_heap.to_a
129
+ end
130
+
131
+ # (see #==)
132
+ def eql?(binary_heap)
133
+ raise ArgumentError, "Undefined method BinaryHeap#eql? for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
134
+ self == binary_heap
135
+ end
136
+
137
+ # Compares contents of the heap, and a heap given as argument.
138
+ #
139
+ # @param binary_heap [BinaryHeap]
140
+ # @raise ArgumentError, if given object is not a heap.
141
+ # @return [true, false] false if heaps are equal, true otherwise
142
+ def !=(binary_heap)
143
+ raise ArgumentError, "Undefined method BinaryHeap#!= for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
144
+ @container != binary_heap.to_a
145
+ end
146
+
147
+ # (see #!=)
148
+ def diff?(binary_heap)
149
+ raise ArgumentError, "Undefined method BinaryHeap#diff? for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
150
+ self != binary_heap
151
+ end
152
+
153
+ # Compares contents of the heap, and a heap given as argument.
154
+ #
155
+ # @param binary_heap [BinaryHeap]
156
+ # @raise ArgumentError, if given object is not a heap.
157
+ # @return
158
+ # => 1 if content of the heap is greater than content of the given heap
159
+ # => 0 if contents are equal
160
+ # => -1 if content of the given heap is greater than content of the heap
161
+ def <=>(binary_heap)
162
+ raise ArgumentError, "Undefined method BinaryHeap#<=> for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
163
+ @container <=> binary_heap.to_a
164
+ end
165
+
166
+ # Concatenates contents of the heap, and a heap given as argument.
167
+ #
168
+ # @param binary_heap [BinaryHeap]
169
+ # @raise ArgumentError, if given object is not a heap
170
+ # @return [BinaryHeap] a new binary heap
171
+ def +(binary_heap)
172
+ raise ArgumentError, "Undefined method BinaryHeap#+ for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
173
+
174
+ BinaryHeap.new(@container + binary_heap.to_a, min: !@max)
175
+ end
176
+
177
+ # (see #+)
178
+ def concat(binary_heap)
179
+ raise ArgumentError, "Undefined method BinaryHeap#concat for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
180
+ self + binary_heap
181
+ end
182
+
183
+ # (see #+)
184
+ def merge(binary_heap)
185
+ raise ArgumentError, "Undefined method BinaryHeap#merge for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
186
+ self + binary_heap
187
+ end
188
+
189
+ # Concatenates contents of the heap, and a heap given as argument.
190
+ #
191
+ # @param binary_heap [BinaryHeap]
192
+ # @raise ArgumentError, if given object is not a heap
193
+ # @return [BinaryHeap] self object
194
+ def concat!(binary_heap)
195
+ raise ArgumentError, "Undefined method BinaryHeap#concat! for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
196
+ from_obj(@container + binary_heap.to_a, false)
197
+ end
198
+
199
+ # Concatenates contents of the heap, and a heap given as argument.
200
+ #
201
+ # @param binary_heap [BinaryHeap]
202
+ # @raise ArgumentError, if given object is not a heap
203
+ # @return [BinaryHeap] self object
204
+ def merge!(binary_heap)
205
+ raise ArgumentError, "Undefined method BinaryHeap#merge! for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
206
+ from_obj(@container + binary_heap.to_a, false)
207
+ end
208
+
209
+ # Unites contents of the heap, and a heap given as argument.
210
+ #
211
+ # @param binary_heap [BinaryHeap]
212
+ # @raise ArgumentError, if given object is not a heap
213
+ # @return [BinaryHeap] a new binary heap
214
+ def |(binary_heap)
215
+ raise ArgumentError, "Undefined method BinaryHeap#| for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
216
+ BinaryHeap.new(@container | binary_heap.to_a, min: !@max)
217
+ end
218
+
219
+ # (see #|)
220
+ def union(binary_heap)
221
+ raise ArgumentError, "Undefined method BinaryHeap#union for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
222
+ self | binary_heap
223
+ end
224
+
225
+ # Unites contents of the heap, and a heap given as argument.
226
+ #
227
+ # @param binary_heap [BinaryHeap]
228
+ # @raise ArgumentError, if given object is not a heap
229
+ # @return [BinaryHeap] self object
230
+ def union!(binary_heap)
231
+ raise ArgumentError, "Undefined method BinaryHeap#union! for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
232
+ from_obj(@container | binary_heap.to_a, false)
233
+ end
234
+
235
+ # Finds the intersection of contents of the heap, and a heap given as argument.
236
+ #
237
+ # @param binary_heap [BinaryHeap]
238
+ # @raise ArgumentError, if given object is not a heap
239
+ # @return [BinaryHeap] a new binary heap
240
+ def &(binary_heap)
241
+ raise ArgumentError, "Undefined method BinaryHeap#& for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
242
+ BinaryHeap.new(@container & binary_heap.to_a, min: !@max)
243
+ end
244
+
245
+ # (see #&)
246
+ def intersect(binary_heap)
247
+ raise ArgumentError, "Undefined method BinaryHeap#intersect for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
248
+ self & binary_heap.to_a
249
+ end
250
+
251
+ # Finds the intersection of contents of the heap, and a heap given as argument.
252
+ #
253
+ # @param binary_heap [BinaryHeap]
254
+ # @raise ArgumentError, if given object is not a heap
255
+ # @return [BinaryHeap] self object
256
+ def intersect!(binary_heap)
257
+ raise ArgumentError, "Undefined method BinaryHeap#intersect! for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
258
+ from_obj(@container & binary_heap.to_a, false)
259
+ end
260
+
261
+ # Finds the difference of contents of the heap, and a heap given as argument.
262
+ #
263
+ # @param binary_heap [BinaryHeap]
264
+ # @raise ArgumentError, if given object is not a heap
265
+ # @return [BinaryHeap] a new binary heap
266
+ def -(binary_heap)
267
+ raise ArgumentError, "Undefined method BinaryHeap#- for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
268
+ BinaryHeap.new(@container - binary_heap.to_a, min: !@max)
269
+ end
270
+
271
+ # (see #-)
272
+ def difference(binary_heap)
273
+ raise ArgumentError, "Undefined method BinaryHeap#difference for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
274
+ self - binary_heap
275
+ end
276
+
277
+ # Finds the difference of contents of the heap, and a heap given as argument.
278
+ #
279
+ # @param binary_heap [BinaryHeap]
280
+ # @raise ArgumentError, if given object is not a heap
281
+ # @return [BinaryHeap] self object
282
+ def difference!(binary_heap)
283
+ raise ArgumentError, "Undefined method BinaryHeap#difference! for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
284
+ from_obj(@container - binary_heap.to_a, false)
285
+ end
286
+
287
+ # Finds the symmetric difference of contents of the heap, and a heap given as argument.
288
+ #
289
+ # @param binary_heap [BinaryHeap]
290
+ # @raise ArgumentError, if given object is not a heap
291
+ # @return [BinaryHeap] a new binary heap
292
+ def ^(binary_heap)
293
+ raise ArgumentError, "Undefined method BinaryHeap#^ for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
294
+ result = (@container | binary_heap.to_a) - (@container & binary_heap.to_a)
295
+ BinaryHeap.new(result, min: !@max)
296
+ end
297
+
298
+ # (see #^)
299
+ def symmetric_difference(binary_heap)
300
+ raise ArgumentError, "Undefined method BinaryHeap#symmetric_difference for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
301
+ self ^ binary_heap
302
+ end
303
+
304
+ # Finds the symmetric difference of contents of the heap, and a heap given as argument.
305
+ #
306
+ # @param binary_heap [BinaryHeap]
307
+ # @raise ArgumentError, if given object is not a heap
308
+ # @return [BinaryHeap] self object
309
+ def symmetric_difference!(binary_heap)
310
+ raise ArgumentError, "Undefined method BinaryHeap#symmetric_difference! for #{binary_heap}:#{binary_heap.class}" unless binary_heap.is_a?(BinaryHeap)
311
+ result = (@container | binary_heap.to_a) - (@container & binary_heap.to_a)
312
+ from_obj(result, false)
313
+ end
314
+
315
+ # Converts content of the heap to an array.
316
+ def to_a
317
+ @container
318
+ end
319
+
320
+ # Clears content of the heap.
321
+ def clear
322
+ @container = []
323
+ self
324
+ end
325
+
326
+ # Filters elements of the heap by given condition.
327
+ #
328
+ # @param block
329
+ # @return [BinaryHeap] a new binary heap
330
+ def select(&block)
331
+ BinaryHeap.new(@container.select { |e| block.call(e)}, min: !@max)
332
+ end
333
+
334
+ # Filters elements of the heap by given condition.
335
+ #
336
+ # @param block
337
+ # @return [BinaryHeap] self object
338
+ def select!(&block)
339
+ from_obj(@container.select { |e| block.call(e)}, false)
340
+ end
341
+
342
+ # (see #select)
343
+ def filter(&block)
344
+ select(&block)
345
+ end
346
+
347
+ # (see #select!)
348
+ def filter!(&block)
349
+ select!(&block)
350
+ end
351
+
352
+ # (see #select)
353
+ def find_all(&block)
354
+ select(&block)
355
+ end
356
+
357
+ # (see #select!)
358
+ def find_all!(&block)
359
+ select!(&block)
360
+ end
361
+
362
+ # Applies a function to each element of the heap.
363
+ #
364
+ # @param block
365
+ # @return [BinaryHeap] a new binary heap
366
+ def map(&block)
367
+ BinaryHeap.new(@container.map { |e| block.call(e)}, min: !@max)
368
+ end
369
+
370
+ # Applies a function to each element of the heap.
371
+ #
372
+ # @param block
373
+ # @return [BinaryHeap] self object
374
+ def map!(&block)
375
+ from_obj(@container.map { |e| block.call(e)}, false)
376
+ end
377
+
378
+ # (see #map)
379
+ def apply(&block)
380
+ map(&block)
381
+ end
382
+
383
+ # (see #map!)
384
+ def apply!(&block)
385
+ map!(&block)
386
+ end
387
+
388
+ private
389
+
390
+ def from_obj(obj, copy)
391
+ raise ArgumentError, "Object doesn't respond to #to_a method" unless obj.respond_to?(:to_a)
392
+ @container = copy ? obj.send(:to_a).dup : obj.send(:to_a)
393
+
394
+ build_heap
395
+ self
396
+ end
397
+
398
+ def heapify(idx)
399
+ return if idx.nil?
400
+ lhs = idx * 2 + 1
401
+ rhs = idx * 2 + 2
402
+ current = idx
403
+
404
+ if !@container[lhs].nil? &&
405
+ ((@max && @container[lhs] > @container[current]) ||
406
+ (!@max && @container[lhs] < @container[current]))
407
+
408
+ current = lhs
409
+ end
410
+
411
+ if !@container[rhs].nil? &&
412
+ ((@max && @container[rhs] > @container[current]) ||
413
+ (!@max && @container[rhs] < @container[current]))
414
+
415
+ current = rhs
416
+ end
417
+
418
+ if current != idx
419
+ @container[idx], @container[current] = @container[current], @container[idx]
420
+ heapify(current)
421
+ end
422
+ end
423
+
424
+ def build_heap
425
+ (@container.length / 2).downto(0) do |idx|
426
+ heapify(idx)
427
+ end
428
+ end
429
+
430
+ def sift_up(idx)
431
+ return if idx.zero?
432
+ parent = idx.even? ? idx / 2 - 1 : idx / 2
433
+
434
+ if (@max && @container[parent] < @container[idx]) || (!@max && @container[parent] > @container[idx])
435
+ @container[parent], @container[idx] = @container[idx], @container[parent]
436
+
437
+ sift_up(parent)
438
+ end
439
+ end
440
+
441
+ def change_key(idx, value, increase: false)
442
+ idx = idx < 0 ? idx + @container.size : idx
443
+ @container[idx] = increase ? (@container[idx] < value ? value : @container[idx]) :
444
+ (@container[idx] > value ? value : @container[idx])
445
+
446
+ sift_up(idx)
447
+ end
448
+
449
+ end
450
+ end
451
+ end
452
+ end
@@ -1,3 +1,3 @@
1
1
  module Algorithmix
2
- VERSION = "0.0.0.4"
2
+ VERSION = "0.0.0.4.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: algorithmix
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0.4
4
+ version: 0.0.0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Monika Ilieva
@@ -68,11 +68,16 @@ dependencies:
68
68
  version: 2.0.0
69
69
  description: |2+
70
70
  Currently the gem contains:
71
+
71
72
  1. Stack
73
+
72
74
  2. Queue
75
+
73
76
  3. Deque
77
+
74
78
  4. Binary heap
75
79
 
80
+
76
81
  email:
77
82
  - "*@*.*"
78
83
  executables: []
@@ -94,6 +99,7 @@ files:
94
99
  - lib/algorithmix/data_structure/generic/deque.rb
95
100
  - lib/algorithmix/data_structure/generic/queue.rb
96
101
  - lib/algorithmix/data_structure/generic/stack.rb
102
+ - lib/algorithmix/data_structure/heap/binary_heap.rb
97
103
  - lib/algorithmix/error.rb
98
104
  - lib/algorithmix/version.rb
99
105
  homepage: https://github.com/monzita/algorithmix/wiki