algorithmable 0.9.0 → 0.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3d896f5d72bec04a61e50d79c670e1ed9379b8cd
4
- data.tar.gz: 701a49b6cb2d478a817baaef1ce743498a62813b
3
+ metadata.gz: e0f425945316b488e5f78067168f54dd56415392
4
+ data.tar.gz: c9dd9353cf0883de156a9860472d18233c227ea2
5
5
  SHA512:
6
- metadata.gz: 45b738fc98edaaf14ee58050bdf24f8d78345fcda7b6d06394d1d6d9cc26dbb9151ea6832f27a3fd05d4906b1c9e80e7fb3d2684e70080574edb1aeacf12e4ab
7
- data.tar.gz: 404eca38ab9c2775ba3f07d6760f2f37cbf303d5b59f36bbbf6fc03af59abe028d3b8bed31ada0c2b747f15eb5eefa92fec78cad1a0bbdaaa9e4c94b0446acfb
6
+ metadata.gz: 6fd0bb3ef1d1f3fe956aaa0fce478fcd1dc474d54b02ea86619802873ab620d181f3e49c7fefaf86c805fdd917f69e00d5a2e6f50f5971d97afb2462a91d62af
7
+ data.tar.gz: 5bdbf61cfb48f980c4d3d3721b7fc48a3f2c6aa26a249753b27bae965e83b41886855cbdae5e5b5904cbc621a3ee03456b826ee0e9345c1b59e338340dee923e
data/README.md CHANGED
@@ -25,7 +25,7 @@ Library also contains solutions for several puzzles solved by implemented algori
25
25
  ## Graph Traversals
26
26
 
27
27
  - Breadth First Search (BFS)
28
- - Death First Search (DFS)
28
+ - Depth First Search (DFS)
29
29
 
30
30
  ## Search Algorithms
31
31
 
@@ -37,6 +37,7 @@ module Algorithmable
37
37
  @succ.each(&block) if @succ
38
38
  end
39
39
  end
40
+ private_constant :Node
40
41
  end
41
42
  end
42
43
  end
@@ -1,10 +1,11 @@
1
1
  module Algorithmable
2
2
  module DataStructs
3
3
  class Deque
4
- include Enumerable
5
4
  include Algorithmable::Errors
6
5
 
7
6
  Node = Struct.new(:prev, :next, :item)
7
+ private_constant :Node
8
+
8
9
  attr_reader :size
9
10
 
10
11
  def initialize(collection = [])
@@ -89,23 +90,37 @@ module Algorithmable
89
90
  end
90
91
 
91
92
  # represent fifo iterator
92
- def each
93
- return unless @front
94
- node = @front
95
- while node
96
- yield node.item
97
- node = node.next
98
- end
93
+ def each(&block)
94
+ collect_items(:forward).each(&block)
99
95
  end
100
96
 
101
97
  # represent lifo iterator
102
- def reverse_each
103
- return unless @back
104
- node = @back
105
- while node
106
- yield node.item
107
- node = node.prev
98
+ def reverse_each(&block)
99
+ collect_items(:backward).each(&block)
100
+ end
101
+
102
+ def to_a
103
+ each.to_a
104
+ end
105
+
106
+ def map(&block)
107
+ each.map(&block)
108
+ end
109
+
110
+ private
111
+
112
+ def collect_items(order)
113
+ variable = order == :backward ? @back : @front
114
+ action = order == :backward ? :prev : :next
115
+ items = []
116
+ if variable
117
+ node = variable
118
+ while node
119
+ items << node.item
120
+ node = node.public_send action
121
+ end
108
122
  end
123
+ items
109
124
  end
110
125
  end
111
126
  end
@@ -95,6 +95,7 @@ module Algorithmable
95
95
  @succ = succ
96
96
  end
97
97
  end
98
+ private_constant :Node
98
99
  end
99
100
  end
100
101
  end
@@ -1,239 +1,13 @@
1
1
  module Algorithmable
2
2
  module DataStructs
3
- #
4
- # Ordered Symbol Table. Implementation using Unbalanced Binary Tree.
5
- #
6
3
  class OrderedSymbolTable
7
- def initialize(key_type, value_type)
8
- @key_type = key_type
9
- @value_type = value_type
10
- @root = nil
11
- end
12
-
13
- def empty?
14
- !size.nonzero?
15
- end
16
-
17
- def size
18
- node_size(@root)
19
- end
20
-
21
- def key?(key)
22
- assert_key_type(key)
23
- !self[key].nil?
24
- end
25
-
26
- def [](key)
27
- assert_key_type(key)
28
- impl_get(@root, key)
29
- end
30
-
31
- def []=(key, value)
32
- assert_value_type(value)
33
- assert_key_type(key)
34
- delete key
35
- @root = impl_put(@root, key, value)
36
- check_tree
37
- end
38
-
39
- def delete_min
40
- @root = impl_delete_min @root
41
- check_tree
42
- end
43
-
44
- def delete_max
45
- @root = impl_delete_max @root
46
- check_tree
47
- end
48
-
49
- def delete(key)
50
- assert_key_type(key)
51
- @root = impl_delete(@root, key)
52
- check_tree
53
- end
54
-
55
- def min
56
- impl_min(@root).key
57
- end
58
-
59
- def max
60
- impl_max(@root).key
61
- end
62
-
63
- def floor(key)
64
- assert_key_type(key)
65
- return unless key || empty?
66
- found = impl_floor(@root, key)
67
- return unless found
68
- found.key
69
- end
70
-
71
- def ceiling(key)
72
- assert_key_type(key)
73
- return unless key || empty?
74
- found = impl_ceiling(@root, key)
75
- return unless found
76
- found.key
77
- end
78
-
79
- def select(integer)
80
- return if integer < 0 || integer >= size
81
- found = impl_select(@root, integer)
82
- found.key
83
- end
84
-
85
- def rank(key)
86
- assert_key_type(key)
87
- return unless key
88
- impl_rank @root, key
89
- end
90
-
91
- private
92
-
93
- def check_tree
94
- true
95
- end
96
-
97
- def assert_value_type(value)
98
- fail "Type expectation not met. Use value type `#{@value_type}` instead." unless value.is_a? @value_type
99
- end
100
-
101
- def assert_key_type(key)
102
- fail "Type expectation not met. Use key type `#{@key_type}` instead." unless key.is_a? @key_type
103
- end
104
-
105
- def impl_rank(node, key)
106
- return 0 unless node
107
- comparison = key <=> node.key
108
- if comparison < 0
109
- impl_rank(node.left, key)
110
- elsif comparison > 0
111
- 1 + node_size(node.left) + impl_rank(node.right, key)
112
- else
113
- node_size node.left
114
- end
115
- end
116
-
117
- def impl_select(node, index)
118
- return unless node
119
- left_size = node_size(node.left)
120
- if left_size > index
121
- impl_select(node.left, index)
122
- elsif left_size < index
123
- impl_select node.right, (index - left_size - 1)
124
- else
125
- node
126
- end
127
- end
128
-
129
- def impl_ceiling(node, key)
130
- return unless node
131
- comparison = key <=> node.key
132
- return node if 0 == comparison
133
- if comparison < 0
134
- found = impl_ceiling(node.left, key)
135
- return found if found
136
- return node
137
- end
138
- impl_ceiling node.right, key
139
- end
140
-
141
- def impl_floor(node, key)
142
- return unless node
143
- comparison = key <=> node.key
144
- return node if 0 == comparison
145
- return impl_floor(node.left, key) if comparison < 0
146
- found = impl_floor(node.right, key)
147
- return found if found
148
- node
149
- end
150
-
151
- def impl_delete(node, key)
152
- return unless node
153
- comparison = key <=> node.key
154
- if comparison < 0
155
- node.left = impl_delete(node.left, key)
156
- elsif comparison > 0
157
- node.right = impl_delete(node.right, key)
158
- else
159
- return unless node.left || node.right
160
- temp = node
161
- node = impl_min(temp.right)
162
- node.right = impl_delete_min(temp.right)
163
- node.left = temp.left
164
- end
165
- node.size = computed_node_size(node)
166
- node
167
- end
168
-
169
- def impl_max(node)
170
- return node unless node.right
171
- impl_max node.right
172
- end
173
-
174
- def impl_min(node)
175
- return node unless node.left
176
- impl_min node.left
177
- end
178
-
179
- def impl_delete_max(node)
180
- return node.left unless node.right
181
- node.right = impl_delete_max(node.right)
182
- node.size = computed_node_size(node)
183
- node
184
- end
185
-
186
- def impl_delete_min(node)
187
- return node.right unless node.left
188
- node.left = impl_delete_min(node.left)
189
- node.size = computed_node_size(node)
190
- node
191
- end
192
-
193
- def impl_put(node, key, value)
194
- return Node.new(key, value, 1) unless node
195
- comparison = key <=> node.key
196
- if comparison < 0
197
- node.left = impl_put(node.left, key, value)
198
- elsif comparison > 0
199
- node.right = impl_put(node.right, key, value)
200
- else
201
- node.value = value
202
- end
203
- node.size = computed_node_size(node)
204
- node
205
- end
206
-
207
- def impl_get(node, key)
208
- return unless node
209
- comparison = key <=> node.key
210
- if comparison < 0
211
- impl_get(node.left, key)
212
- elsif comparison > 0
213
- impl_get(node.right, key)
214
- else
215
- node.value
216
- end
217
- end
218
-
219
- def node_size(node)
220
- node.nil? ? 0 : node.size
221
- end
222
-
223
- def computed_node_size(node)
224
- 1 + node_size(node.left) + node_size(node.right)
225
- end
4
+ extend Forwardable
226
5
 
227
- class Node
228
- attr_accessor :key, :value, :left, :right, :size
6
+ def_delegators :@imp, :[]=, :[], :key?, :empty?, :size, :keys, :max, :min, :floor, :ceiling, :rank, :delete
229
7
 
230
- def initialize(key = nil, value = nil, size = 0)
231
- @key = key
232
- @value = value
233
- @left = nil
234
- @right = nil
235
- @size = size
236
- end
8
+ def initialize(key_type, value_type)
9
+ search_strategy_factory = Object.new.extend Algorithmable::Searches
10
+ @imp = search_strategy_factory.new_binary_search_tree(key_type, value_type)
237
11
  end
238
12
  end
239
13
  end
@@ -2,10 +2,9 @@ module Algorithmable
2
2
  module DataStructs
3
3
  class Queue
4
4
  include Algorithmable::Errors
5
- include Enumerable
6
5
  extend Forwardable
7
6
 
8
- def_delegators :@imp, :empty?, :size, :each
7
+ def_delegators :@imp, :empty?, :size, :each, :map, :to_a
9
8
 
10
9
  def initialize(collection = [])
11
10
  @imp = Deque.new collection
@@ -2,10 +2,9 @@ module Algorithmable
2
2
  module DataStructs
3
3
  class Stack
4
4
  include Algorithmable::Errors
5
- include Enumerable
6
5
  extend Forwardable
7
6
 
8
- def_delegators :@imp, :empty?, :size, :each
7
+ def_delegators :@imp, :empty?, :size, :each, :map, :to_a
9
8
 
10
9
  def initialize(collection = [])
11
10
  @imp = Deque.new
@@ -1,6 +1,6 @@
1
1
  module Algorithmable
2
- module Search
3
- class Binary
2
+ module Searches
3
+ class BinarySearch
4
4
  def self.lookup(element, in_collection)
5
5
  new.lookup(element, in_collection)
6
6
  end
@@ -0,0 +1,291 @@
1
+ module Algorithmable
2
+ module Searches
3
+ class BinarySearchTree
4
+ def initialize(key_type, value_type)
5
+ @key_type = key_type
6
+ @value_type = value_type
7
+ @root = nil
8
+ end
9
+
10
+ def empty?
11
+ !size.nonzero?
12
+ end
13
+
14
+ def size
15
+ node_size(@root)
16
+ end
17
+
18
+ def key?(key)
19
+ assert_key_type(key)
20
+ !self[key].nil?
21
+ end
22
+
23
+ def [](key)
24
+ assert_key_type(key)
25
+ impl_get(@root, key)
26
+ end
27
+
28
+ def []=(key, value)
29
+ assert_value_type(value)
30
+ assert_key_type(key)
31
+ delete key
32
+ @root = impl_put(@root, key, value)
33
+ check_tree_consistency
34
+ end
35
+
36
+ def delete_min
37
+ @root = impl_delete_min @root
38
+ check_tree_consistency
39
+ end
40
+
41
+ def delete_max
42
+ @root = impl_delete_max @root
43
+ check_tree_consistency
44
+ end
45
+
46
+ def delete(key)
47
+ assert_key_type(key)
48
+ @root = impl_delete(@root, key)
49
+ check_tree_consistency
50
+ end
51
+
52
+ def min
53
+ return if empty?
54
+ impl_min(@root).key
55
+ end
56
+
57
+ def max
58
+ return if empty?
59
+ impl_max(@root).key
60
+ end
61
+
62
+ def floor(key)
63
+ assert_key_type(key)
64
+ return unless key || empty?
65
+ found = impl_floor(@root, key)
66
+ return unless found
67
+ found.key
68
+ end
69
+
70
+ def ceiling(key)
71
+ assert_key_type(key)
72
+ return unless key || empty?
73
+ found = impl_ceiling(@root, key)
74
+ return unless found
75
+ found.key
76
+ end
77
+
78
+ def select(integer)
79
+ return if integer < 0 || integer >= size
80
+ found = impl_select(@root, integer)
81
+ found.key
82
+ end
83
+
84
+ def rank(key)
85
+ assert_key_type(key)
86
+ return unless key
87
+ impl_rank @root, key
88
+ end
89
+
90
+ def size_consistent?
91
+ impl_size_consistent?(@root)
92
+ end
93
+
94
+ def rank_consistent?
95
+ size.times do |time|
96
+ break false unless time != rank(select(time))
97
+ end
98
+ keys.each do |key|
99
+ comparison = key <=> select(rank(key))
100
+ break false if comparison != 0
101
+ end
102
+ true
103
+ end
104
+
105
+ def symmetric_ordered?
106
+ impl_symmetric_ordered? @root
107
+ end
108
+
109
+ def keys(low = min, high = max)
110
+ queue = Algorithmable::DataStructs::Queue.new
111
+ impl_keys @root, queue, low, high
112
+ queue
113
+ end
114
+
115
+ private
116
+
117
+ def check_tree_consistency
118
+ $stderr.puts 'Tree is not in symmetric order' unless a = symmetric_ordered?
119
+ $stderr.puts 'Tree has size inconsistency' unless b = size_consistent?
120
+ $stderr.puts 'Tree has ranking inconsistency' unless c = rank_consistent?
121
+ a && b && c
122
+ end
123
+
124
+ def impl_symmetric_ordered?(node, min_key = nil, max_key = nil)
125
+ return true unless node
126
+ return false if !min_key.nil? && (node.key <=> min_key) <= 0
127
+ return false if !max_key.nil? && (node.key <=> max_key) >= 0
128
+ impl_symmetric_ordered?(node.left, min_key, node.key) && impl_symmetric_ordered?(node.right, node.key, max_key)
129
+ end
130
+
131
+ def impl_keys(node, queue, low, high)
132
+ return unless node
133
+ cmp_low = low <=> node.key
134
+ cmp_high = high <=> node.key
135
+ impl_keys(node.left, queue, low, high) if cmp_low < 0
136
+ queue.enqueue node.key if cmp_low <= 0 && cmp_high >= 0
137
+ impl_keys(node.right, queue, low, high) if cmp_high > 0
138
+ end
139
+
140
+ def impl_size_consistent?(node)
141
+ return true unless node
142
+ return false if (node.size != node_size(node.left) + node_size(node.right) + 1)
143
+ impl_size_consistent?(node.left) && impl_size_consistent?(node.right)
144
+ end
145
+
146
+ def assert_value_type(value)
147
+ fail "Type expectation not met. Use value type `#{@value_type}` instead." unless value.is_a? @value_type
148
+ end
149
+
150
+ def assert_key_type(key)
151
+ fail "Type expectation not met. Use key type `#{@key_type}` instead." unless key.is_a? @key_type
152
+ end
153
+
154
+ def impl_rank(node, key)
155
+ return 0 unless node
156
+ comparison = key <=> node.key
157
+ if comparison < 0
158
+ impl_rank(node.left, key)
159
+ elsif comparison > 0
160
+ 1 + node_size(node.left) + impl_rank(node.right, key)
161
+ else
162
+ node_size node.left
163
+ end
164
+ end
165
+
166
+ def impl_select(node, index)
167
+ return unless node
168
+ left_size = node_size(node.left)
169
+ if left_size > index
170
+ impl_select(node.left, index)
171
+ elsif left_size < index
172
+ impl_select node.right, (index - left_size - 1)
173
+ else
174
+ node
175
+ end
176
+ end
177
+
178
+ def impl_ceiling(node, key)
179
+ return unless node
180
+ comparison = key <=> node.key
181
+ return node if 0 == comparison
182
+ if comparison < 0
183
+ found = impl_ceiling(node.left, key)
184
+ return found if found
185
+ return node
186
+ end
187
+ impl_ceiling node.right, key
188
+ end
189
+
190
+ def impl_floor(node, key)
191
+ return unless node
192
+ comparison = key <=> node.key
193
+ return node if 0 == comparison
194
+ return impl_floor(node.left, key) if comparison < 0
195
+ found = impl_floor(node.right, key)
196
+ return found if found
197
+ node
198
+ end
199
+
200
+ def impl_delete(node, key)
201
+ return unless node
202
+ comparison = key <=> node.key
203
+ if comparison < 0
204
+ node.left = impl_delete(node.left, key)
205
+ elsif comparison > 0
206
+ node.right = impl_delete(node.right, key)
207
+ else
208
+ return node.right if node.left.nil?
209
+ return node.left if node.right.nil?
210
+ temp = node
211
+ node = impl_min(temp.right)
212
+ node.right = impl_delete_min(temp.right)
213
+ node.left = temp.left
214
+ end
215
+ node.size = computed_node_size(node)
216
+ node
217
+ end
218
+
219
+ def impl_max(node)
220
+ return node unless node.right
221
+ impl_max node.right
222
+ end
223
+
224
+ def impl_min(node)
225
+ return node unless node.left
226
+ impl_min node.left
227
+ end
228
+
229
+ def impl_delete_max(node)
230
+ return node.left unless node.right
231
+ node.right = impl_delete_max(node.right)
232
+ node.size = computed_node_size(node)
233
+ node
234
+ end
235
+
236
+ def impl_delete_min(node)
237
+ return node.right unless node.left
238
+ node.left = impl_delete_min(node.left)
239
+ node.size = computed_node_size(node)
240
+ node
241
+ end
242
+
243
+ def impl_put(node, key, value)
244
+ return Node.new(key, value, 1) unless node
245
+ comparison = key <=> node.key
246
+ if comparison < 0
247
+ node.left = impl_put(node.left, key, value)
248
+ elsif comparison > 0
249
+ node.right = impl_put(node.right, key, value)
250
+ else
251
+ node.value = value
252
+ end
253
+ node.size = computed_node_size(node)
254
+ node
255
+ end
256
+
257
+ def impl_get(node, key)
258
+ return unless node
259
+ comparison = key <=> node.key
260
+ if comparison < 0
261
+ impl_get(node.left, key)
262
+ elsif comparison > 0
263
+ impl_get(node.right, key)
264
+ else
265
+ node.value
266
+ end
267
+ end
268
+
269
+ def node_size(node)
270
+ node.nil? ? 0 : node.size
271
+ end
272
+
273
+ def computed_node_size(node)
274
+ 1 + node_size(node.left) + node_size(node.right)
275
+ end
276
+
277
+ class Node
278
+ attr_accessor :key, :value, :left, :right, :size
279
+
280
+ def initialize(key = nil, value = nil, size = 0)
281
+ @key = key
282
+ @value = value
283
+ @left = nil
284
+ @right = nil
285
+ @size = size
286
+ end
287
+ end
288
+ private_constant :Node
289
+ end
290
+ end
291
+ end
@@ -0,0 +1,14 @@
1
+ module Algorithmable
2
+ module Searches
3
+ autoload :BinarySearch, 'algorithmable/search/binary_search'
4
+ autoload :BinarySearchTree, 'algorithmable/search/binary_search_tree'
5
+
6
+ def binary_search(element, collection)
7
+ BinarySearch.lookup(element, collection)
8
+ end
9
+
10
+ def new_binary_search_tree(key_type, value_type)
11
+ BinarySearchTree.new key_type, value_type
12
+ end
13
+ end
14
+ end
@@ -1,3 +1,3 @@
1
1
  module Algorithmable
2
- VERSION = '0.9.0'
2
+ VERSION = '0.10.0'
3
3
  end
data/lib/algorithmable.rb CHANGED
@@ -7,7 +7,7 @@ require 'English'
7
7
  module Algorithmable
8
8
  autoload :Errors, 'algorithmable/errors'
9
9
  autoload :Sort, 'algorithmable/sort'
10
- autoload :Search, 'algorithmable/search'
10
+ autoload :Searches, 'algorithmable/searches'
11
11
  autoload :DataStructs, 'algorithmable/data_structs'
12
12
  autoload :Graphs, 'algorithmable/graphs'
13
13
  autoload :Puzzles, 'algorithmable/puzzles'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: algorithmable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roman Lishtaba
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-01-09 00:00:00.000000000 Z
11
+ date: 2016-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -157,8 +157,9 @@ files:
157
157
  - lib/algorithmable/puzzles.rb
158
158
  - lib/algorithmable/puzzles/dijkstras_two_stacks.rb
159
159
  - lib/algorithmable/puzzles/josephus_problem.rb
160
- - lib/algorithmable/search.rb
161
- - lib/algorithmable/search/binary.rb
160
+ - lib/algorithmable/search/binary_search.rb
161
+ - lib/algorithmable/search/binary_search_tree.rb
162
+ - lib/algorithmable/searches.rb
162
163
  - lib/algorithmable/sort.rb
163
164
  - lib/algorithmable/sort/binary_heap.rb
164
165
  - lib/algorithmable/sort/bubble.rb
@@ -1,11 +0,0 @@
1
- module Algorithmable
2
- module Search
3
- autoload :Binary, 'algorithmable/search/binary'
4
-
5
- class << self
6
- def binary(element, collection)
7
- Binary.lookup(element, collection)
8
- end
9
- end
10
- end
11
- end