algorithmix 0.0.0.4 → 0.0.0.4.1

Sign up to get free protection for your applications and to get access to all the features.
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