Class: Btree::Node

Inherits:
Object
  • Object
show all
Defined in:
lib/btree/node.rb

Instance Method Summary collapse

Constructor Details

#initialize(degree) ⇒ Node

Returns a new instance of Node.



14
15
16
17
18
# File 'lib/btree/node.rb', line 14

def initialize(degree)
  @degree = degree
  @keys = []
  @children = []
end

Instance Method Details

#add_child(node) ⇒ Object



33
34
35
# File 'lib/btree/node.rb', line 33

def add_child(node)
  @children << node
end

#childrenObject



37
38
39
# File 'lib/btree/node.rb', line 37

def children
  @children.dup.freeze
end

#dump(level = 0) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/btree/node.rb', line 20

def dump(level = 0)
  @keys.each_with_index do |key, idx|
    puts "LEVEL: #{level} => #{key.first}: full? #{full?} leaf? #{leaf?} children: #{values.inspect}"
    if @children[idx]
       @children[idx].dump(level + 1)
    end
  end
  (@children[@keys.size..-1] || []).each do |c|
    c.dump(level+1)
  end
  nil
end

#full?Boolean

Returns:

  • (Boolean)


49
50
51
# File 'lib/btree/node.rb', line 49

def full?
  size >= 2 * @degree - 1
end

#insert(key, value) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/btree/node.rb', line 105

def insert(key, value)
  # The slot the key would occupy is also the slot it would already occupy if
  # it were present, so locating it and rejecting a duplicate are one step.
  # Checked at every node on the way down, not just at the leaf: a key that a
  # split has promoted into an internal node would otherwise be descended
  # past and inserted a second time, hiding one copy in a subtree.
  i = key_index(key)
  raise "Duplicate key" if i < size && @keys[i].first == key

  if leaf?
    @keys.insert(i, [key, value])
  else
    if @children[i] && @children[i].full?
      split(i)
      # The split just promoted a key into this node, after the check above.
      raise "Duplicate key" if @keys[i].first == key
      i += 1 if key > @keys[i].first
    end
    @children[i].insert(key, value)
  end
end

#keysObject



41
42
43
# File 'lib/btree/node.rb', line 41

def keys
  @keys.map(&:first).freeze
end

#leaf?Boolean

Returns:

  • (Boolean)


53
54
55
# File 'lib/btree/node.rb', line 53

def leaf?
  @children.length == 0
end

#sizeObject



57
58
59
# File 'lib/btree/node.rb', line 57

def size
  @keys.size
end

#split(child_idx) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/btree/node.rb', line 127

def split(child_idx)
  raise "Invalid child index #{child_idx} in split, num_children = #{@children.size}" if child_idx < 0 || child_idx >= @children.size
  #puts "SPLIT1: #{self.inspect}"
  splitee = @children[child_idx]
  y = Btree::Node.new(@degree)
  z = Btree::Node.new(@degree)
  (@degree-1).times do |j|
    z._keys[j] = splitee._keys[j+@degree]
    y._keys[j] = splitee._keys[j]
  end
  if !splitee.leaf?
    @degree.times do |j|
      z._children[j] = splitee._children[j+@degree]
      y._children[j] = splitee._children[j]
    end
  end
  mid_val = splitee._keys[@degree-1]
  #puts "SPLIT2: #{self.inspect}"
  (@keys.size).downto(child_idx) do |j|
    @children[j+1] = @children[j]
  end

  @children[child_idx+1] = z
  @children[child_idx] = y
  
  #puts "SPLIT3: #{self.inspect}"

  (@keys.size - 1).downto(child_idx) do |j|
    @keys[j+1] = @keys[j]
  end

  #puts "SPLIT4: #{self.inspect}"

  @keys[child_idx] = mid_val
  #puts "SPLIT5: #{self.inspect}"
end

#value_of(key) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/btree/node.rb', line 90

def value_of(key)

  return values_of(key) if key.kind_of? Range

  i = key_index(key)

  if i < size && key == @keys[i].first
    return @keys[i].last
  elsif leaf?
    return nil
  else
    return @children[i].value_of(key)
  end
end

#valuesObject



45
46
47
# File 'lib/btree/node.rb', line 45

def values
  @keys.map(&:last).freeze
end

#values_of(range) ⇒ Object

Values whose keys fall in the range, in key order. Subtrees that cannot contain an in-range key are never visited.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/btree/node.rb', line 63

def values_of(range)

  result = Array.new
  lo = range.begin
  hi = range.end

  # Skip the keys, and the subtrees between them, that sort entirely below
  # the range.  When every key is below it, this lands on the rightmost
  # child, which may still hold in-range keys.
  i = lo ? key_index(lo) : 0

  result += @children[i].values_of(range) if !leaf? && @children[i]

  while i < size
    key = @keys[i].first
    # Everything from here on sorts above the range.
    break if hi && (range.exclude_end? ? key >= hi : key > hi)
    result << @keys[i].last if range.cover? key
    result += @children[i+1].values_of(range) if !leaf? && @children[i+1]
    i += 1
  end

  result

end