compsci 0.0.3.1 → 0.1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +63 -14
- data/VERSION +1 -1
- data/compsci.gemspec +5 -22
- data/examples/binary_tree.rb +11 -6
- data/examples/complete_tree.rb +47 -0
- data/examples/heap.rb +19 -7
- data/examples/tree.rb +41 -0
- data/lib/compsci.rb +1 -2
- data/lib/compsci/complete_tree.rb +109 -0
- data/lib/compsci/fibonacci.rb +31 -30
- data/lib/compsci/fit.rb +135 -135
- data/lib/compsci/heap.rb +14 -108
- data/lib/compsci/names.rb +132 -0
- data/lib/compsci/node.rb +67 -0
- data/lib/compsci/timer.rb +30 -29
- data/lib/compsci/tree.rb +48 -138
- data/test/bench/tree.rb +2 -2
- data/test/complete_tree.rb +131 -0
- data/test/heap.rb +121 -34
- data/test/names.rb +96 -0
- data/test/node.rb +89 -0
- data/test/tree.rb +49 -237
- metadata +24 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3df760b020e177135c9d73e20f455635ca82250c
|
4
|
+
data.tar.gz: '0850e990c79b14fa39533e0990d707cb3f1fe7cc'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8997da4e5f98d35b1250d8feab97d9e46d7a193aec42a89b74e720bfff50608624b054e7e3bb85709230d2a038557919c3a2ce0d6f9f4dc22ddf88e8357d6c8c
|
7
|
+
data.tar.gz: 90069e7be2f383c80e0edd09c41ca566ba8481b3659c4aca90c7b23000027c3eaa1139cf980ba74737ca9ba4d20e99bd0591623be7b5872d9d7cb06ac99ce2ad
|
data/README.md
CHANGED
@@ -1,28 +1,70 @@
|
|
1
1
|
[![Build Status](https://travis-ci.org/rickhull/compsci.svg?branch=master)](https://travis-ci.org/rickhull/compsci)
|
2
2
|
|
3
|
-
#
|
3
|
+
# CompSci
|
4
4
|
|
5
5
|
Provided are some toy implementations for some basic computer science problems.
|
6
6
|
|
7
|
-
## [`
|
8
|
-
|
9
|
-
* `Node`
|
10
|
-
|
11
|
-
|
12
|
-
* `
|
13
|
-
|
14
|
-
|
7
|
+
## [`Node`](lib/compsci/node.rb) data structure
|
8
|
+
|
9
|
+
* `Node`
|
10
|
+
- `@value`
|
11
|
+
- `@children`
|
12
|
+
* `ChildNode` adds
|
13
|
+
- `@parent`
|
14
|
+
- `#gen`
|
15
|
+
- `#siblings`
|
16
|
+
|
17
|
+
## [`Tree`](lib/compsci/tree.rb) data structures
|
18
|
+
|
19
|
+
* `Tree`
|
20
|
+
- `@root`
|
21
|
+
- `#df_search`
|
22
|
+
- `#bf_search`
|
23
|
+
* `NaryTree`
|
24
|
+
- `@child_slots` (number of children per node)
|
25
|
+
- `#open_parent` O(n) to find a node with open child slots
|
26
|
+
- `#push` append `#open_parent.children`
|
27
|
+
- `#display` if initialized with `ChildNode`
|
28
|
+
* `BinaryTree`
|
29
|
+
- `NaryTree.new(child_slots: 2)`
|
30
|
+
- `#display` for `Node` and `ChildNode`
|
31
|
+
* `TernaryTree`
|
32
|
+
- `NaryTree.new(child_slots: 3)`
|
33
|
+
* `QuaternaryTree`
|
34
|
+
- `NaryTree.new(child_slots: 4)`
|
35
|
+
|
36
|
+
## [`CompleteNaryTree`](lib/compsci/complete_tree.rb) data structure
|
37
|
+
|
38
|
+
Efficient Array implementation of a complete tree.
|
39
|
+
|
40
|
+
* `CompleteNaryTree`
|
41
|
+
- `CompleteNaryTree.parent_idx`
|
42
|
+
- `CompleteNaryTree.children_idx`
|
43
|
+
- `CompleteNaryTree.gen`
|
44
|
+
- `@array`
|
45
|
+
- `@child_slots`
|
46
|
+
- `#push`
|
47
|
+
- `#pop`
|
48
|
+
- `#size`
|
49
|
+
- `#last_idx`
|
50
|
+
- `#display` (alias `#to_s`)
|
51
|
+
* `CompleteBinaryTree`
|
52
|
+
- `CompleteNaryTree.new(child_slots: 2)`
|
53
|
+
* `CompleteTernaryTree`
|
54
|
+
- `CompleteNaryTree.new(child_slots: 3)`
|
55
|
+
* `CompleteQuaternaryTree`
|
56
|
+
- `CompleteNaryTree.new(child_slots: 4)`
|
15
57
|
|
16
58
|
## [`Heap`](lib/compsci/heap.rb) data structure
|
17
59
|
|
18
|
-
|
19
|
-
|
60
|
+
`CompleteNaryTree` implementation. Both minheaps and maxheaps are supported.
|
61
|
+
Any number of children may be provided via `child_slots`. The primary
|
62
|
+
operations are `Heap#push` and `Heap#pop`. See the
|
20
63
|
[heap example](examples/heap.rb) which can be executed (among other examples)
|
21
64
|
via `rake examples`.
|
22
65
|
|
23
|
-
|
24
|
-
|
25
|
-
second, constant up past 1M pushes.
|
66
|
+
My basic Vagrant VM gets around 500k pushes per second, constant up past 1M
|
67
|
+
pushes.
|
26
68
|
|
27
69
|
## [`Fibonacci`](lib/compsci/fibonacci.rb) functions
|
28
70
|
|
@@ -93,3 +135,10 @@ cumulative: 0.828
|
|
93
135
|
* `Fit.linear` - fits `y = a + bx`; returns a, b, r^2
|
94
136
|
* `Fit.exponential` fits `y = ae^(bx)`; returns a, b, r^2
|
95
137
|
* `Fit.power` fits `y = ax^b`; returns a, b, r^2
|
138
|
+
|
139
|
+
## [`Names`](lib/compsci/names.rb) functions
|
140
|
+
|
141
|
+
* `Names.assign`
|
142
|
+
* `Names::Greek.upper`
|
143
|
+
* `Names::Greek.lower`
|
144
|
+
* `Names::Greek.symbol`
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.1.0.1
|
data/compsci.gemspec
CHANGED
@@ -10,28 +10,11 @@ Gem::Specification.new do |s|
|
|
10
10
|
|
11
11
|
s.version = File.read(File.join(__dir__, 'VERSION')).chomp
|
12
12
|
|
13
|
-
s.files = %w[
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
Rakefile
|
18
|
-
lib/compsci.rb
|
19
|
-
lib/compsci/fibonacci.rb
|
20
|
-
lib/compsci/fit.rb
|
21
|
-
lib/compsci/heap.rb
|
22
|
-
lib/compsci/timer.rb
|
23
|
-
lib/compsci/tree.rb
|
24
|
-
examples/binary_tree.rb
|
25
|
-
examples/heap.rb
|
26
|
-
test/fibonacci.rb
|
27
|
-
test/fit.rb
|
28
|
-
test/heap.rb
|
29
|
-
test/timer.rb
|
30
|
-
test/tree.rb
|
31
|
-
test/bench/fibonacci.rb
|
32
|
-
test/bench/heap.rb
|
33
|
-
test/bench/tree.rb
|
34
|
-
]
|
13
|
+
s.files = %w[compsci.gemspec VERSION README.md Rakefile]
|
14
|
+
s.files += Dir['lib/**/*.rb']
|
15
|
+
s.files += Dir['test/**/*.rb']
|
16
|
+
s.files += Dir['examples/**/*.rb']
|
35
17
|
|
36
18
|
s.add_development_dependency "minitest", "~> 5.0"
|
19
|
+
s.add_development_dependency "rake", "~> 0"
|
37
20
|
end
|
data/examples/binary_tree.rb
CHANGED
@@ -13,7 +13,7 @@ EOF
|
|
13
13
|
count = 0
|
14
14
|
start = Timer.now
|
15
15
|
start_1k = Timer.now
|
16
|
-
tree =
|
16
|
+
tree = NaryTree.new(ChildNode, rand(99), child_slots: 2)
|
17
17
|
|
18
18
|
loop {
|
19
19
|
count += 1
|
@@ -47,20 +47,25 @@ puts <<EOF
|
|
47
47
|
|
48
48
|
EOF
|
49
49
|
|
50
|
-
vals =
|
51
|
-
30.times { vals << rand(99) }
|
50
|
+
vals = Array.new(30) { rand 99 }
|
52
51
|
p vals
|
53
52
|
|
54
|
-
tree =
|
53
|
+
tree = NaryTree.new(ChildNode, vals.shift, child_slots: 2)
|
55
54
|
tree.push vals.shift until vals.empty?
|
56
|
-
|
57
55
|
puts tree
|
58
56
|
|
57
|
+
p tree
|
58
|
+
puts
|
59
|
+
|
59
60
|
tree.df_search { |n|
|
60
61
|
puts "visited #{n}"
|
61
62
|
false # or n.value > 90
|
62
63
|
}
|
63
64
|
puts
|
64
65
|
|
65
|
-
|
66
|
+
vals = Array.new(30) { rand 99 }
|
67
|
+
puts "push: #{vals.inspect}"
|
68
|
+
|
69
|
+
tree.push vals.shift until vals.empty?
|
70
|
+
puts tree
|
66
71
|
puts
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'compsci/complete_tree'
|
2
|
+
require 'compsci/timer'
|
3
|
+
|
4
|
+
include CompSci
|
5
|
+
|
6
|
+
puts <<EOF
|
7
|
+
#
|
8
|
+
# Print CompleteBinary-, Ternary-, and QuaternaryTree
|
9
|
+
#
|
10
|
+
|
11
|
+
EOF
|
12
|
+
|
13
|
+
vals = Array.new(30) { rand 99 }
|
14
|
+
|
15
|
+
[CompleteBinaryTree,
|
16
|
+
CompleteTernaryTree,
|
17
|
+
CompleteQuaternaryTree,
|
18
|
+
].each { |tree_class|
|
19
|
+
# start with the same vals for each class
|
20
|
+
my_vals = vals.dup
|
21
|
+
p my_vals
|
22
|
+
tree = tree_class.new
|
23
|
+
tree.push my_vals.shift until my_vals.empty?
|
24
|
+
p tree
|
25
|
+
puts tree.display(width: 80)
|
26
|
+
puts
|
27
|
+
puts
|
28
|
+
puts
|
29
|
+
|
30
|
+
|
31
|
+
# TODO: add CompleteTree#df_search
|
32
|
+
# tree.df_search { |n|
|
33
|
+
# puts "visited #{n}"
|
34
|
+
# false # or n.value > 90
|
35
|
+
# }
|
36
|
+
# puts
|
37
|
+
|
38
|
+
# push different vals for each class
|
39
|
+
my_vals = Array.new(30) { rand 99 }
|
40
|
+
puts "push: #{my_vals.inspect}"
|
41
|
+
|
42
|
+
tree.push my_vals.shift until my_vals.empty?
|
43
|
+
puts tree.display(width: 80)
|
44
|
+
puts
|
45
|
+
puts
|
46
|
+
puts
|
47
|
+
}
|
data/examples/heap.rb
CHANGED
@@ -13,7 +13,7 @@ EOF
|
|
13
13
|
count = 0
|
14
14
|
start = Timer.now
|
15
15
|
start_100k = Timer.now
|
16
|
-
h =
|
16
|
+
h = Heap.new
|
17
17
|
|
18
18
|
loop {
|
19
19
|
count += 1
|
@@ -47,24 +47,36 @@ puts
|
|
47
47
|
|
48
48
|
puts <<EOF
|
49
49
|
#
|
50
|
-
#
|
50
|
+
# display the results of TernaryHeap push and pop
|
51
51
|
#
|
52
52
|
|
53
53
|
EOF
|
54
54
|
|
55
|
-
h = Heap.new
|
55
|
+
h = Heap.new(child_slots: 3)
|
56
56
|
|
57
|
-
puts "push: %s" % Array.new(
|
58
|
-
puts "
|
57
|
+
puts "push: %s" % Array.new(30) { rand(99).tap { |i| h.push i } }.join(' ')
|
58
|
+
puts "array: #{h.array.inspect}"
|
59
59
|
puts "heap: #{h.heap?}"
|
60
|
+
puts h
|
61
|
+
puts
|
60
62
|
puts
|
61
63
|
|
62
64
|
puts "pop: %i" % h.pop
|
63
|
-
puts "
|
65
|
+
puts "array: #{h.array.inspect}"
|
64
66
|
puts "heap: #{h.heap?}"
|
67
|
+
puts h
|
68
|
+
puts
|
65
69
|
puts
|
66
70
|
|
67
71
|
puts "pop: %s" % Array.new(9) { h.pop }.join(' ')
|
68
|
-
puts "
|
72
|
+
puts "array: #{h.array.inspect}"
|
73
|
+
puts "heap: #{h.heap?}"
|
74
|
+
puts h
|
75
|
+
puts
|
76
|
+
puts
|
77
|
+
|
78
|
+
puts "push: %s" % Array.new(30) { rand(99).tap { |i| h.push i } }.join(' ')
|
79
|
+
puts "array: #{h.array.inspect}"
|
69
80
|
puts "heap: #{h.heap?}"
|
81
|
+
puts h
|
70
82
|
puts
|
data/examples/tree.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'compsci/tree'
|
2
|
+
require 'compsci/timer'
|
3
|
+
|
4
|
+
include CompSci
|
5
|
+
|
6
|
+
puts <<EOF
|
7
|
+
#
|
8
|
+
# Try out Binary-, Ternary-, and QuaternaryTree
|
9
|
+
#
|
10
|
+
|
11
|
+
EOF
|
12
|
+
|
13
|
+
vals = Array.new(30) { rand 99 }
|
14
|
+
|
15
|
+
[BinaryTree, TernaryTree, QuaternaryTree].each { |tree_class|
|
16
|
+
# start with the same vals for each class
|
17
|
+
my_vals = vals.dup
|
18
|
+
p my_vals
|
19
|
+
tree = tree_class.new(ChildNode, my_vals.shift)
|
20
|
+
tree.push my_vals.shift until my_vals.empty?
|
21
|
+
p tree
|
22
|
+
puts tree.display(width: 80)
|
23
|
+
puts
|
24
|
+
visited = []
|
25
|
+
tree.df_search { |n|
|
26
|
+
visited << n
|
27
|
+
false # or n.value > 90
|
28
|
+
}
|
29
|
+
puts "df_search visited: %s" % visited.join(' ')
|
30
|
+
puts
|
31
|
+
puts
|
32
|
+
|
33
|
+
# push different vals for each class
|
34
|
+
my_vals = Array.new(30) { rand 99 }
|
35
|
+
puts "push: #{my_vals.inspect}"
|
36
|
+
tree.push my_vals.shift until my_vals.empty?
|
37
|
+
puts
|
38
|
+
puts tree.display(width: 80)
|
39
|
+
puts
|
40
|
+
puts
|
41
|
+
}
|
data/lib/compsci.rb
CHANGED
@@ -1,2 +1 @@
|
|
1
|
-
module CompSci
|
2
|
-
end
|
1
|
+
module CompSci; end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module CompSci
|
2
|
+
# A CompleteNaryTree can very efficiently use an array for storage using
|
3
|
+
# simple arithmetic to determine parent child relationships.
|
4
|
+
#
|
5
|
+
# It is kept separate from compsci/tree as it does not require compsci/node
|
6
|
+
#
|
7
|
+
class CompleteNaryTree
|
8
|
+
# integer math maps several children to one parent
|
9
|
+
def self.parent_idx(idx, n)
|
10
|
+
(idx-1) / n
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.children_idx(idx, n)
|
14
|
+
Array.new(n) { |i| n*idx + i + 1 }
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.gen(idx, n)
|
18
|
+
count = 0
|
19
|
+
loop {
|
20
|
+
pidx = self.parent_idx(idx, n)
|
21
|
+
break if pidx < 0
|
22
|
+
count += 1
|
23
|
+
idx = pidx
|
24
|
+
}
|
25
|
+
count
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :array
|
29
|
+
|
30
|
+
def initialize(array: [], child_slots: 2)
|
31
|
+
@array = array
|
32
|
+
@child_slots = child_slots
|
33
|
+
end
|
34
|
+
|
35
|
+
def push val
|
36
|
+
@array.push val
|
37
|
+
end
|
38
|
+
|
39
|
+
def pop
|
40
|
+
@array.pop
|
41
|
+
end
|
42
|
+
|
43
|
+
def size
|
44
|
+
@array.size
|
45
|
+
end
|
46
|
+
|
47
|
+
def last_idx
|
48
|
+
@array.size - 1 unless @array.empty?
|
49
|
+
end
|
50
|
+
|
51
|
+
# or, ya know, just iterate @array
|
52
|
+
def bf_search(&blk)
|
53
|
+
destinations = [0]
|
54
|
+
while !destinations.empty?
|
55
|
+
idx = destinations.shift
|
56
|
+
return idx if yield @array[idx]
|
57
|
+
|
58
|
+
# idx has a val and the block is false
|
59
|
+
# add existent children to destinations
|
60
|
+
self.class.children_idx(idx, @child_slots).each { |cidx|
|
61
|
+
destinations.push(cidx) if cidx < @array.size
|
62
|
+
}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def df_search(&blk)
|
67
|
+
puts "not yet"
|
68
|
+
end
|
69
|
+
|
70
|
+
def display(width: 80)
|
71
|
+
str = ''
|
72
|
+
old_level = 0
|
73
|
+
@array.each_with_index { |val, i|
|
74
|
+
val = val.to_s
|
75
|
+
level = self.class.gen(i, @child_slots)
|
76
|
+
if old_level != level
|
77
|
+
str += "\n"
|
78
|
+
old_level = level
|
79
|
+
end
|
80
|
+
|
81
|
+
# center in block_width
|
82
|
+
slots = @child_slots**level
|
83
|
+
block_width = width / slots
|
84
|
+
space = [(block_width + val.size) / 2, val.size + 1].max
|
85
|
+
str += val.ljust(space, ' ').rjust(block_width, ' ')
|
86
|
+
}
|
87
|
+
str
|
88
|
+
end
|
89
|
+
alias_method :to_s, :display
|
90
|
+
end
|
91
|
+
|
92
|
+
class CompleteBinaryTree < CompleteNaryTree
|
93
|
+
def initialize(array: [])
|
94
|
+
super(array: array, child_slots: 2)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class CompleteTernaryTree < CompleteNaryTree
|
99
|
+
def initialize(array: [])
|
100
|
+
super(array: array, child_slots: 3)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class CompleteQuaternaryTree < CompleteNaryTree
|
105
|
+
def initialize(array: [])
|
106
|
+
super(array: array, child_slots: 4)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/lib/compsci/fibonacci.rb
CHANGED
@@ -1,39 +1,40 @@
|
|
1
|
-
require 'compsci'
|
2
1
|
autoload :Matrix, 'matrix'
|
3
2
|
|
4
|
-
module CompSci
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
module CompSci
|
4
|
+
class Fibonacci
|
5
|
+
def self.classic(n)
|
6
|
+
n < 2 ? n : classic(n-1) + classic(n-2)
|
7
|
+
end
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
def self.cache_recursive(n, cache = {})
|
10
|
+
return n if n < 2
|
11
|
+
cache[n] ||= cache_recursive(n-1, cache) + cache_recursive(n-2, cache)
|
12
|
+
end
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
def self.cache_iterative(n)
|
15
|
+
cache = [0, 1]
|
16
|
+
2.upto(n) { |i| cache[i] = cache[i-1] + cache[i-2] }
|
17
|
+
cache[n]
|
18
|
+
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
20
|
+
# traditional
|
21
|
+
def self.dynamic(n)
|
22
|
+
a, b = 0, 1
|
23
|
+
n.times { a, b = b, a+b }
|
24
|
+
a
|
25
|
+
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
# fails for n == 0
|
28
|
+
def self.dynamic_fast(n)
|
29
|
+
a, b = 0, 1
|
30
|
+
(n-1).times { a, b = b, a+b }
|
31
|
+
b
|
32
|
+
end
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
# https://gist.github.com/havenwood/02cf291b809327d96a3f
|
35
|
+
# slower than dynamic until around n == 500
|
36
|
+
def self.matrix(n)
|
37
|
+
(Matrix[[0, 1], [1, 1]] ** n.pred)[1, 1].to_i
|
38
|
+
end
|
38
39
|
end
|
39
40
|
end
|