algorithmable 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/algorithmable.gemspec +1 -0
- data/lib/algorithmable/cache/imp.rb +19 -0
- data/lib/algorithmable/cache/primitive_max_heap.rb +38 -0
- data/lib/algorithmable/cache/primitive_min_heap.rb +38 -0
- data/lib/algorithmable/cache.rb +15 -0
- data/lib/algorithmable/cups/circular_dependencies.rb +27 -0
- data/lib/algorithmable/cups/longest_common_subsequence.rb +46 -0
- data/lib/algorithmable/cups/merge_two_arrays.rb +31 -0
- data/lib/algorithmable/cups/nested_lists_problem.rb +105 -0
- data/lib/algorithmable/cups/number_of_occurrences_in_array.rb +49 -0
- data/lib/algorithmable/cups/primitives.rb +205 -2
- data/lib/algorithmable/cups/root_cube_issue.rb +39 -0
- data/lib/algorithmable/cups/stacks_and_queues/stack_sorter.rb +25 -0
- data/lib/algorithmable/cups/stacks_and_queues/stack_with_min.rb +23 -0
- data/lib/algorithmable/cups/stacks_and_queues/towers_of_hanoi.rb +48 -0
- data/lib/algorithmable/cups/stacks_and_queues/triple_stack.rb +52 -0
- data/lib/algorithmable/cups/stacks_and_queues/two_stacks_queue.rb +37 -0
- data/lib/algorithmable/cups/stacks_and_queues.rb +31 -0
- data/lib/algorithmable/cups/stocks.rb +80 -0
- data/lib/algorithmable/cups/task_shedule_with_coldtime.rb +16 -0
- data/lib/algorithmable/cups/two_sum.rb +59 -0
- data/lib/algorithmable/cups.rb +7 -0
- data/lib/algorithmable/data_structs/linked_list/base.rb +21 -1
- data/lib/algorithmable/data_structs/linked_list/doubly.rb +1 -1
- data/lib/algorithmable/data_structs/linked_list/singly.rb +62 -1
- data/lib/algorithmable/data_structs/queue.rb +4 -0
- data/lib/algorithmable/data_structs/stack.rb +4 -0
- data/lib/algorithmable/data_structs/tree/binary.rb +10 -0
- data/lib/algorithmable/data_structs/tree/binary_search.rb +206 -0
- data/lib/algorithmable/data_structs/tree.rb +13 -0
- data/lib/algorithmable/data_structs.rb +6 -0
- data/lib/algorithmable/sort/bubble.rb +9 -16
- data/lib/algorithmable/sort/insertion.rb +24 -0
- data/lib/algorithmable/sort/merge.rb +4 -8
- data/lib/algorithmable/sort/quick_sort.rb +35 -0
- data/lib/algorithmable/sort/selection.rb +23 -0
- data/lib/algorithmable/sort/shell.rb +27 -0
- data/lib/algorithmable/sort/shuffle.rb +15 -0
- data/lib/algorithmable/sort/utils.rb +66 -0
- data/lib/algorithmable/sort.rb +28 -0
- data/lib/algorithmable/union_find.rb +51 -0
- data/lib/algorithmable/version.rb +1 -1
- data/lib/algorithmable.rb +2 -0
- data/script/benchmarks/sort.rb +37 -0
- metadata +46 -2
@@ -3,7 +3,7 @@ module Algorithmable
|
|
3
3
|
module LinkedList
|
4
4
|
class Singly < Base
|
5
5
|
class Node
|
6
|
-
attr_accessor :item, :next
|
6
|
+
attr_accessor :item, :next, :front
|
7
7
|
|
8
8
|
def initialize(item, next_pointer = nil)
|
9
9
|
@item = item
|
@@ -93,8 +93,69 @@ module Algorithmable
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
+
def merge(other)
|
97
|
+
front = recursive_merge_imp self.front, other.front
|
98
|
+
list = self.class.new
|
99
|
+
while front
|
100
|
+
list.push_back front.item
|
101
|
+
front = front.next
|
102
|
+
end
|
103
|
+
list
|
104
|
+
end
|
105
|
+
|
106
|
+
def reverse!
|
107
|
+
@back = @front
|
108
|
+
@front = reverse_imp @front
|
109
|
+
self
|
110
|
+
end
|
111
|
+
|
112
|
+
def sort!
|
113
|
+
sort_linked_list @front
|
114
|
+
end
|
115
|
+
|
96
116
|
private
|
97
117
|
|
118
|
+
def sort_linked_list(node)
|
119
|
+
return unless node || node.empty?
|
120
|
+
swapped = false
|
121
|
+
prev = nil
|
122
|
+
|
123
|
+
begin
|
124
|
+
swapped = false
|
125
|
+
current = node
|
126
|
+
|
127
|
+
until current.next == prev
|
128
|
+
if current.item > current.next.item
|
129
|
+
swap_nodes current, current.next
|
130
|
+
swapped = true
|
131
|
+
end
|
132
|
+
current = current.next
|
133
|
+
end
|
134
|
+
|
135
|
+
prev = current
|
136
|
+
end while swapped
|
137
|
+
end
|
138
|
+
|
139
|
+
def swap_nodes(node1, node2)
|
140
|
+
tmp = node1.item
|
141
|
+
node1.item = node2.item
|
142
|
+
node2.item = tmp
|
143
|
+
end
|
144
|
+
|
145
|
+
def recursive_merge_imp(node1, node2)
|
146
|
+
return node2 if node1.nil?
|
147
|
+
return node1 if node2.nil?
|
148
|
+
node1 = node1.dup
|
149
|
+
node2 = node2.dup
|
150
|
+
if node1.item < node2.item
|
151
|
+
node1.next = recursive_merge_imp(node1.next, node2)
|
152
|
+
node1
|
153
|
+
else
|
154
|
+
node2.next = recursive_merge_imp(node2.next, node1)
|
155
|
+
node2
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
98
159
|
def reverse_imp(root)
|
99
160
|
return root if root.nil? || root.next.nil?
|
100
161
|
node = reverse_imp(root.next)
|
@@ -0,0 +1,206 @@
|
|
1
|
+
module Algorithmable
|
2
|
+
module DataStructs
|
3
|
+
module Tree
|
4
|
+
class BinarySearch
|
5
|
+
include Enumerable
|
6
|
+
include Algorithmable::DataStructs
|
7
|
+
|
8
|
+
def initialize(collection = [])
|
9
|
+
@root = nil
|
10
|
+
collection.each { |item| put item }
|
11
|
+
end
|
12
|
+
|
13
|
+
def max_depth
|
14
|
+
max_height_of @root
|
15
|
+
end
|
16
|
+
|
17
|
+
alias_method :height, :max_depth
|
18
|
+
|
19
|
+
def min_depth
|
20
|
+
min_height_of @root
|
21
|
+
end
|
22
|
+
|
23
|
+
def size
|
24
|
+
size_of @root
|
25
|
+
end
|
26
|
+
|
27
|
+
def empty?
|
28
|
+
0 == size
|
29
|
+
end
|
30
|
+
|
31
|
+
def put(object)
|
32
|
+
@root = put_impl @root, object
|
33
|
+
end
|
34
|
+
|
35
|
+
def min
|
36
|
+
return if empty?
|
37
|
+
min_impl(@root).item
|
38
|
+
end
|
39
|
+
|
40
|
+
def max
|
41
|
+
return if empty?
|
42
|
+
max_impl(@root).item
|
43
|
+
end
|
44
|
+
|
45
|
+
def each(&block)
|
46
|
+
each_with_dfs(&block)
|
47
|
+
end
|
48
|
+
|
49
|
+
def each_with_dfs(&block)
|
50
|
+
tmp = collect_nodes_with_dfs(@root).to_a
|
51
|
+
block_given? ? tmp.each(&block) : tmp
|
52
|
+
end
|
53
|
+
|
54
|
+
def each_with_bfs(&block)
|
55
|
+
tmp = collect_nodes_with_bfs(@root).to_a
|
56
|
+
block_given? ? tmp.each(&block) : tmp
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_print
|
60
|
+
return if empty?
|
61
|
+
queue = new_fifo_queue
|
62
|
+
level = 0
|
63
|
+
next_level = 1
|
64
|
+
out = []
|
65
|
+
queue.enqueue @root
|
66
|
+
until queue.empty?
|
67
|
+
level += 1
|
68
|
+
node = queue.dequeue
|
69
|
+
out << node.item << ' '
|
70
|
+
queue.enqueue node.left if node.left
|
71
|
+
queue.enqueue node.right if node.right
|
72
|
+
|
73
|
+
if level == next_level
|
74
|
+
next_level += queue.size
|
75
|
+
out << "\n"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
out.join
|
79
|
+
end
|
80
|
+
|
81
|
+
def reverse!
|
82
|
+
@root = reverse_bang_impl @root
|
83
|
+
end
|
84
|
+
|
85
|
+
def flip!
|
86
|
+
@root = flip_bang_imp! @root, 0
|
87
|
+
end
|
88
|
+
|
89
|
+
def flip_bang_imp!(n, count)
|
90
|
+
return unless n
|
91
|
+
return n unless n.left && n.right
|
92
|
+
new_head = flip_bang_imp! n.left, count + 1
|
93
|
+
n.left.left = n.right
|
94
|
+
n.left.right = n
|
95
|
+
if count == 0
|
96
|
+
n.left = nil
|
97
|
+
n.right = nil
|
98
|
+
end
|
99
|
+
new_head
|
100
|
+
end
|
101
|
+
|
102
|
+
def balanced?(diff = 1)
|
103
|
+
(max_depth - min_depth) <= diff
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def max_height_of(node)
|
109
|
+
return 0 unless node
|
110
|
+
1 + [max_height_of(node.left), max_height_of(node.right)].max
|
111
|
+
end
|
112
|
+
|
113
|
+
def min_height_of(node)
|
114
|
+
return 0 unless node
|
115
|
+
1 + [min_height_of(node.left), min_height_of(node.right)].min
|
116
|
+
end
|
117
|
+
|
118
|
+
def reverse_bang_impl(root)
|
119
|
+
return unless root
|
120
|
+
reverse_bang_impl root.left
|
121
|
+
reverse_bang_impl root.right
|
122
|
+
tmp = root.left
|
123
|
+
root.left = root.right
|
124
|
+
root.right = tmp
|
125
|
+
root
|
126
|
+
end
|
127
|
+
|
128
|
+
def collect_nodes_with_bfs(root)
|
129
|
+
queue = new_fifo_queue
|
130
|
+
stack = new_lifo_queue
|
131
|
+
queue.enqueue root
|
132
|
+
until queue.empty?
|
133
|
+
node = queue.dequeue
|
134
|
+
stack.push node.item
|
135
|
+
queue.enqueue node.left if node.left
|
136
|
+
queue.enqueue node.right if node.right
|
137
|
+
end
|
138
|
+
stack
|
139
|
+
end
|
140
|
+
|
141
|
+
def collect_nodes_with_dfs(node)
|
142
|
+
stack = []
|
143
|
+
dfs_impl node, stack
|
144
|
+
stack
|
145
|
+
end
|
146
|
+
|
147
|
+
# in-order traversal
|
148
|
+
def dfs_impl(node, stack)
|
149
|
+
dfs_impl node.left, stack if node.left
|
150
|
+
stack.push node.item
|
151
|
+
dfs_impl node.right, stack if node.right
|
152
|
+
end
|
153
|
+
|
154
|
+
def max_impl(node)
|
155
|
+
return node if node.right.nil?
|
156
|
+
max_impl(node.right)
|
157
|
+
end
|
158
|
+
|
159
|
+
def min_impl(node)
|
160
|
+
return node if node.left.nil?
|
161
|
+
min_impl(node.left)
|
162
|
+
end
|
163
|
+
|
164
|
+
def put_impl(node, object)
|
165
|
+
return make_node(object, 1) unless node
|
166
|
+
case object <=> node.item
|
167
|
+
when -1
|
168
|
+
node.left = put_impl(node.left, object)
|
169
|
+
when 1
|
170
|
+
node.right = put_impl(node.right, object)
|
171
|
+
else
|
172
|
+
node.item = object
|
173
|
+
end
|
174
|
+
node.size = 1 + size_of(node.left) + size_of(node.right)
|
175
|
+
node
|
176
|
+
end
|
177
|
+
|
178
|
+
def size_of(node)
|
179
|
+
return 0 if node.nil?
|
180
|
+
node.size
|
181
|
+
end
|
182
|
+
|
183
|
+
def make_node(object, size)
|
184
|
+
Node.new object, size
|
185
|
+
end
|
186
|
+
|
187
|
+
class Node
|
188
|
+
attr_accessor :item, :left, :right, :size
|
189
|
+
|
190
|
+
def initialize(value, size)
|
191
|
+
@item = value
|
192
|
+
@size = size
|
193
|
+
@left = nil
|
194
|
+
@right = nil
|
195
|
+
end
|
196
|
+
|
197
|
+
def <=>(other)
|
198
|
+
@item <=> other.item
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
private_constant :Node
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Algorithmable
|
2
|
+
module DataStructs
|
3
|
+
module Tree
|
4
|
+
autoload :Binary, 'algorithmable/data_structs/tree/binary'
|
5
|
+
autoload :BinarySearch, 'algorithmable/data_structs/tree/binary_search'
|
6
|
+
autoload :Node, 'algorithmable/data_structs/tree/node'
|
7
|
+
|
8
|
+
def new_ordered_binary_tree(collection = [])
|
9
|
+
BinarySearch.new(collection)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -7,8 +7,10 @@ module Algorithmable
|
|
7
7
|
autoload :Stack, 'algorithmable/data_structs/stack'
|
8
8
|
autoload :OrderedSymbolTable, 'algorithmable/data_structs/ordered_symbol_table'
|
9
9
|
autoload :Heap, 'algorithmable/data_structs/heap'
|
10
|
+
autoload :Tree, 'algorithmable/data_structs/tree'
|
10
11
|
|
11
12
|
include LinkedList
|
13
|
+
include Tree
|
12
14
|
|
13
15
|
def new_bag
|
14
16
|
Bag.new
|
@@ -22,6 +24,10 @@ module Algorithmable
|
|
22
24
|
Stack.new
|
23
25
|
end
|
24
26
|
|
27
|
+
def new_deque_queue
|
28
|
+
Deque.new
|
29
|
+
end
|
30
|
+
|
25
31
|
def new_ordered_symbol_table(key_type, value_type)
|
26
32
|
OrderedSymbolTable.new(key_type, value_type)
|
27
33
|
end
|
@@ -1,16 +1,18 @@
|
|
1
1
|
module Algorithmable
|
2
2
|
module Sort
|
3
3
|
class Bubble
|
4
|
+
extend Algorithmable::Sort::Utils
|
5
|
+
#
|
6
|
+
# Time О(N^2), stable and slow
|
7
|
+
# Space О(N)
|
8
|
+
#
|
4
9
|
def self.sort(collection)
|
5
|
-
|
6
|
-
end
|
7
|
-
|
8
|
-
def sort(collection)
|
10
|
+
length = collection.length - 1
|
9
11
|
loop do
|
10
12
|
swapped = false
|
11
|
-
(
|
12
|
-
if (collection[
|
13
|
-
|
13
|
+
0.upto(length).each do |i|
|
14
|
+
if 1 == (collection[i] <=> collection[i + 1])
|
15
|
+
swap(collection, i)
|
14
16
|
swapped = true
|
15
17
|
end
|
16
18
|
end
|
@@ -18,15 +20,6 @@ module Algorithmable
|
|
18
20
|
end
|
19
21
|
collection
|
20
22
|
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def swap(index, collection)
|
25
|
-
current = collection[index]
|
26
|
-
collection[index] = collection[index.next]
|
27
|
-
collection[index.next] = current
|
28
|
-
collection
|
29
|
-
end
|
30
23
|
end
|
31
24
|
end
|
32
25
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Algorithmable
|
2
|
+
module Sort
|
3
|
+
class Insertion
|
4
|
+
extend Algorithmable::Sort::Utils
|
5
|
+
#
|
6
|
+
# Time О(N^2), stable and slow
|
7
|
+
# Space Complexity: О(N)
|
8
|
+
#
|
9
|
+
def self.sort(collection)
|
10
|
+
return collection if 2 > collection.length
|
11
|
+
1.upto(collection.length - 1).each do |i|
|
12
|
+
curr_char = collection[i]
|
13
|
+
j = i - 1
|
14
|
+
while 0 <= j && collection[j] > curr_char
|
15
|
+
collection[j + 1] = collection[j]
|
16
|
+
j -= 1
|
17
|
+
end
|
18
|
+
collection[j + 1] = curr_char
|
19
|
+
end
|
20
|
+
collection
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -2,20 +2,16 @@ module Algorithmable
|
|
2
2
|
module Sort
|
3
3
|
class Merge
|
4
4
|
def self.sort(collection)
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
def sort(collection)
|
9
|
-
return collection if collection.size <= 1
|
10
|
-
mid = collection.size / 2
|
5
|
+
return collection if collection.length <= 1
|
6
|
+
mid = collection.length / 2
|
11
7
|
left = collection[0...mid]
|
12
|
-
right = collection[mid...collection.
|
8
|
+
right = collection[mid...collection.length]
|
13
9
|
merge(sort(left), sort(right))
|
14
10
|
end
|
15
11
|
|
16
12
|
private
|
17
13
|
|
18
|
-
def merge(left, right)
|
14
|
+
def self.merge(left, right)
|
19
15
|
sorted = []
|
20
16
|
until left.empty? || right.empty?
|
21
17
|
left.first <= right.first ? sorted << left.shift : sorted << right.shift
|