Skip to content

Commit 202b355

Browse files
committed
major cleanup
- remove CompleteBinary / Ternary / QuaternaryTree classes - rework how generations are calculated (and cached)
1 parent e6e7b11 commit 202b355

File tree

5 files changed

+45
-100
lines changed

5 files changed

+45
-100
lines changed

README.md

-6
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,6 @@ determine parent/child relationships.
6969
- `#size`
7070
- `#last_idx`
7171
- `#display` - alias `#to_s`
72-
* `CompleteBinaryTree < CompleteTree`
73-
- `@child_slots = 2`
74-
* `CompleteTernaryTree < CompleteTree`
75-
- `@child_slots = 3`
76-
* `CompleteQuaternaryTree < CompleteTree`
77-
- `@child_slots = 4`
7872

7973
* [examples/complete_tree.rb](examples/complete_tree.rb)
8074
* [test/complete_tree.rb](test/complete_tree.rb)

examples/complete_tree.rb

+5-11
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,18 @@
33
include CompSci
44

55
vals = Array.new(30) { rand 99 }
6+
puts "initial vals: #{vals.inspect}"
67

7-
[CompleteBinaryTree,
8-
CompleteTernaryTree,
9-
CompleteQuaternaryTree].each { |tree_class|
10-
8+
[2, 3, 4].each { |child_slots|
119
puts <<EOF
1210
1311
#
14-
# Print #{tree_class} filled with static vals
12+
# Print CompleteTree(#{child_slots}) filled with static vals
1513
#
1614
1715
EOF
1816

19-
my_vals = vals.dup
20-
puts "initial vals: #{my_vals.inspect}"
21-
tree = tree_class.new
22-
tree.push my_vals.shift until my_vals.empty?
23-
17+
tree = CompleteTree.new(array: vals, child_slots: child_slots)
2418
p tree
2519
puts
2620
puts tree.display(width: 80)
@@ -36,7 +30,7 @@
3630
EOF
3731

3832
my_vals = Array.new(30) { rand 99 }
39-
puts "new vals: #{my_vals.inspect}"
33+
puts "added vals: #{my_vals.inspect}"
4034

4135
tree.push my_vals.shift until my_vals.empty?
4236
puts

lib/compsci/complete_tree.rb

+33-60
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,45 @@
33
module CompSci
44
# A CompleteTree can very efficiently use an array for storage using
55
# simple arithmetic to determine parent child relationships.
6+
# Any type of value may be stored in the array / tree at any location.
67
#
78
class CompleteTree
89
class WIP < RuntimeError; end
910

10-
# integer math maps several children to one parent
11+
# given a child index and child count (e.g. 2 for a binary tree)
12+
# integer math maps several children to one parent index
1113
def self.parent_idx(idx, n)
1214
(idx-1) / n
1315
end
1416

17+
# given a parent index and child count
18+
# integer math maps several children to one parent index
1519
def self.children_idx(idx, n)
1620
Array.new(n) { |i| n*idx + i + 1 }
1721
end
1822

23+
GEN = {}
24+
[2, 3, 4, 5, 6].each { |n|
25+
cursor = -1
26+
GEN[n] = Array.new(10) { |i| cursor += n**i }
27+
}
28+
29+
def self.gen_lookup(idx, n)
30+
return nil unless GEN[n]
31+
return nil unless idx <= GEN[n].last
32+
GEN[n].each.with_index { |max, level| return level if idx <= max }
33+
nil
34+
end
35+
1936
def self.gen(idx, n)
20-
count = 0
21-
loop {
22-
pidx = self.parent_idx(idx, n)
23-
break if pidx < 0
24-
count += 1
25-
idx = pidx
26-
}
27-
count
37+
return 0 if idx <= 0
38+
gen_lookup(idx, n) or gen(self.parent_idx(idx, n), n) + 1
39+
end
40+
41+
# return generation level and sibling count at that level
42+
def self.generation(idx, n)
43+
level = gen(idx, n)
44+
[level, n ** level]
2845
end
2946

3047
attr_reader :array
@@ -50,65 +67,21 @@ def last_idx
5067
@array.size - 1 unless @array.empty?
5168
end
5269

53-
# or, ya know, just iterate @array
54-
def bf_search(&blk)
55-
raise(WIP)
56-
destinations = [0]
57-
while !destinations.empty?
58-
idx = destinations.shift
59-
return idx if yield @array[idx]
60-
61-
# idx has a val and the block is false
62-
# add existent children to destinations
63-
self.class.children_idx(idx, @child_slots).each { |cidx|
64-
destinations.push(cidx) if cidx < @array.size
65-
}
66-
end
67-
end
68-
69-
def df_search(&blk)
70-
raise(WIP)
71-
end
72-
73-
# TODO: fixme
7470
def display(width: 80)
75-
raise(WIP)
76-
str = ''
77-
old_level = 0
71+
result = []
72+
level = 0
7873
@array.each_with_index { |val, i|
7974
val = val.to_s
80-
level = self.class.gen(i, @child_slots)
81-
if old_level != level
82-
str += NEWLINE
83-
old_level = level
84-
end
75+
level, slots = self.class.generation(i, @child_slots)
76+
block_width = width / slots
8577

8678
# center in block_width
87-
slots = @child_slots**level
88-
block_width = width / slots
8979
space = [(block_width + val.size) / 2, val.size + 1].max
90-
str += val.ljust(space, ' ').rjust(block_width, ' ')
80+
result[level] ||= ''
81+
result[level] += val.ljust(space, ' ').rjust(block_width, ' ')
9182
}
92-
str
83+
result
9384
end
9485
alias_method :to_s, :display
9586
end
96-
97-
class CompleteBinaryTree < CompleteTree
98-
def initialize(array: [])
99-
super(array: array, child_slots: 2)
100-
end
101-
end
102-
103-
class CompleteTernaryTree < CompleteTree
104-
def initialize(array: [])
105-
super(array: array, child_slots: 3)
106-
end
107-
end
108-
109-
class CompleteQuaternaryTree < CompleteTree
110-
def initialize(array: [])
111-
super(array: array, child_slots: 4)
112-
end
113-
end
11487
end

sig/complete_tree.rbs

+6-22
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,24 @@ module CompSci
33
# simple arithmetic to determine parent child relationships.
44
#
55
class CompleteTree
6-
@array: Array[Integer]
6+
@array: Array[untyped]
77
@child_slots: Integer
88

99
def self.parent_idx: (Integer idx, Integer n) -> Integer
1010
def self.children_idx: (Integer idx, Integer n) -> Array[Integer]
11+
def self.gen_lookup: (Integer idx, Integer n) -> Integer
1112
def self.gen: (Integer idx, Integer n) -> Integer
13+
def self.generation: (Integer idx, Integer n) -> [Integer, Integer]
1214

13-
attr_reader array: Array[Integer]
15+
attr_reader array: Array[untyped]
1416

15-
def initialize: (?array: Array[Integer], ?child_slots: Integer) -> void
17+
def initialize: (?array: Array[untyped], ?child_slots: Integer) -> void
1618

1719
def push: (untyped val) -> untyped
1820
def pop: () -> untyped
1921
def size: () -> Integer
2022
def last_idx: () -> (Integer | nil)
21-
def bf_search: () { (untyped) -> untyped } -> untyped
22-
23-
def df_search: () { (?) -> untyped } -> untyped
24-
25-
# TODO: fixme
26-
def display: (?width: ::Integer) -> untyped
27-
23+
def display: (?width: Integer) -> Array[String]
2824
alias to_s display
2925
end
30-
31-
class CompleteBinaryTree < CompleteTree
32-
def initialize: (?array: untyped) -> void
33-
end
34-
35-
class CompleteTernaryTree < CompleteTree
36-
def initialize: (?array: untyped) -> void
37-
end
38-
39-
class CompleteQuaternaryTree < CompleteTree
40-
def initialize: (?array: untyped) -> void
41-
end
4226
end

test/complete_tree.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@
117117
before do
118118
@array = (0..99).sort_by { rand }
119119
@empty = CompleteTree.new(child_slots: 5)
120-
@nonempty = CompleteQuaternaryTree.new(array: @array)
120+
@nonempty = CompleteTree.new(array: @array, child_slots: 4)
121121
end
122122

123123
it "must have a size" do

0 commit comments

Comments
 (0)