Skip to content

Commit fbdeb4f

Browse files
committed
Refactor shared array-backed tree API helpers
Extract common collection and serialization-related instance methods into Tree::Utils::ArrayTreeApiMethods and use it in FenwickTree and SegmentTree while preserving public behavior.
1 parent a254ca4 commit fbdeb4f

4 files changed

Lines changed: 129 additions & 154 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ Changes section to scan for breaking or behavioral changes.
1717
* Refactor shared binary heap internals into
1818
`Tree::Utils::HeapSharedMethods` to reduce duplication between min-heap and
1919
max-heap implementations without changing public behavior.
20+
* Refactor shared array-backed tree API helpers into
21+
`Tree::Utils::ArrayTreeApiMethods` and use it in `Tree::FenwickTree` and
22+
`Tree::SegmentTree` without changing public behavior.
2023
* Make `Tree::TrieNode#<<` use trie word-insert semantics (`insert(word)`)
2124
instead of generic child-node attachment semantics.
2225
* Add `<<` insertion shorthand to `Tree::AATree` and `Tree::BTree` for

lib/tree/fenwicktree.rb

Lines changed: 2 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
# frozen_string_literal: true
3939

4040
require 'json'
41+
require_relative 'utils/array_tree_api_methods'
4142

4243
module Tree
4344
# Provides a Fenwick (binary indexed) tree implementation.
@@ -63,6 +64,7 @@ module Tree
6364
class FenwickTree
6465
include Enumerable
6566
include Comparable
67+
include Tree::Utils::ArrayTreeApiMethods
6668

6769
# @!attribute [r] size
6870
# Size of the tree (number of elements).
@@ -92,26 +94,6 @@ def initialize(size, values = nil)
9294
end
9395
end
9496

95-
# Convenience synonym for {#size}.
96-
#
97-
# @return [Integer] The number of elements tracked by the tree.
98-
def length
99-
size
100-
end
101-
102-
# Iterate over values in index order.
103-
#
104-
# @yieldparam value [Numeric] Value at each index.
105-
#
106-
# @return [Tree::FenwickTree] The receiver, if a block is given.
107-
# @return [Enumerator] An enumerator, if no block is given.
108-
def each(&)
109-
return to_enum(:each) unless block_given?
110-
111-
0.upto(@size - 1) { |index| yield self[index] }
112-
self
113-
end
114-
11597
# Add a delta to the value at the specified index.
11698
#
11799
# @param [Integer] index Zero-based index to update.
@@ -200,37 +182,6 @@ def []=(index, delta)
200182
self[index]
201183
end
202184

203-
# Returns all values in index order.
204-
#
205-
# @return [Array<Numeric>] Values in index order.
206-
def values
207-
to_a
208-
end
209-
210-
# Returns all indices in order.
211-
#
212-
# @return [Array<Integer>] Indices in order.
213-
def keys
214-
(0...@size).to_a
215-
end
216-
217-
# Returns all values as an Array.
218-
#
219-
# @return [Array<Numeric>] Values in index order.
220-
def to_a
221-
map { |value| value }
222-
end
223-
224-
# Returns a Hash representation of the tree.
225-
#
226-
# @return [Hash] Hash representation of the Fenwick tree.
227-
def to_h
228-
{
229-
size: size,
230-
values: to_a
231-
}
232-
end
233-
234185
# Build a Fenwick tree from a Hash representation.
235186
#
236187
# @param [Hash] hash Hash representation of a Fenwick tree.
@@ -251,22 +202,6 @@ def self.from_hash(hash)
251202
new(size, values)
252203
end
253204

254-
# JSON serialization for the Fenwick tree.
255-
#
256-
# @param [Hash] _options JSON serialization options.
257-
# @return [Hash] Hash representation for JSON serialization.
258-
def as_json(_options = {})
259-
to_h
260-
end
261-
262-
# Serialize the Fenwick tree to JSON.
263-
#
264-
# @param [Array] args JSON.generate arguments.
265-
# @return [String] JSON representation of the tree.
266-
def to_json(*args)
267-
JSON.generate(as_json, *args)
268-
end
269-
270205
# Create a Fenwick tree from a JSON hash.
271206
#
272207
# @param [Hash] json_hash JSON hash representation.
@@ -275,16 +210,6 @@ def self.json_create(json_hash)
275210
from_hash(json_hash)
276211
end
277212

278-
# Compare Fenwick trees by their ordered values.
279-
#
280-
# @param [Tree::FenwickTree] other The Fenwick tree to compare.
281-
# @return [Integer, nil] -1, 0, 1, or +nil+ if not comparable.
282-
def <=>(other)
283-
return nil unless other.is_a?(Tree::FenwickTree)
284-
285-
to_a <=> other.to_a
286-
end
287-
288213
private
289214

290215
# Validate the size for the tree.

lib/tree/segmenttree.rb

Lines changed: 2 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
# frozen_string_literal: true
3838

3939
require 'json'
40+
require_relative 'utils/array_tree_api_methods'
4041

4142
module Tree
4243
# Provides a Segment Tree implementation for range sum queries.
@@ -61,6 +62,7 @@ module Tree
6162
class SegmentTree
6263
include Enumerable
6364
include Comparable
65+
include Tree::Utils::ArrayTreeApiMethods
6466

6567
# @!attribute [r] size
6668
# Size of the tree (number of elements).
@@ -90,26 +92,6 @@ def initialize(size, values = nil)
9092
end
9193
end
9294

93-
# Convenience synonym for {#size}.
94-
#
95-
# @return [Integer] The number of elements tracked by the tree.
96-
def length
97-
size
98-
end
99-
100-
# Iterate over values in index order.
101-
#
102-
# @yieldparam value [Numeric] Value at each index.
103-
#
104-
# @return [Tree::SegmentTree] The receiver, if a block is given.
105-
# @return [Enumerator] An enumerator, if no block is given.
106-
def each(&)
107-
return to_enum(:each) unless block_given?
108-
109-
0.upto(@size - 1) { |index| yield self[index] }
110-
self
111-
end
112-
11395
# Set the value at the specified index.
11496
#
11597
# @param [Integer] index Zero-based index to update.
@@ -173,37 +155,6 @@ def []=(index, value)
173155
self[index]
174156
end
175157

176-
# Returns all values in index order.
177-
#
178-
# @return [Array<Numeric>] Values in index order.
179-
def values
180-
to_a
181-
end
182-
183-
# Returns all indices in order.
184-
#
185-
# @return [Array<Integer>] Indices in order.
186-
def keys
187-
(0...@size).to_a
188-
end
189-
190-
# Returns all values as an Array.
191-
#
192-
# @return [Array<Numeric>] Values in index order.
193-
def to_a
194-
map { |value| value }
195-
end
196-
197-
# Returns a Hash representation of the tree.
198-
#
199-
# @return [Hash] Hash representation of the segment tree.
200-
def to_h
201-
{
202-
size: size,
203-
values: to_a
204-
}
205-
end
206-
207158
# Build a segment tree from a Hash representation.
208159
#
209160
# @param [Hash] hash Hash representation of a segment tree.
@@ -224,22 +175,6 @@ def self.from_hash(hash)
224175
new(size, values)
225176
end
226177

227-
# JSON serialization for the segment tree.
228-
#
229-
# @param [Hash] _options JSON serialization options.
230-
# @return [Hash] Hash representation for JSON serialization.
231-
def as_json(_options = {})
232-
to_h
233-
end
234-
235-
# Serialize the segment tree to JSON.
236-
#
237-
# @param [Array] args JSON.generate arguments.
238-
# @return [String] JSON representation of the tree.
239-
def to_json(*args)
240-
JSON.generate(as_json, *args)
241-
end
242-
243178
# Create a segment tree from a JSON hash.
244179
#
245180
# @param [Hash] json_hash JSON hash representation.
@@ -248,16 +183,6 @@ def self.json_create(json_hash)
248183
from_hash(json_hash)
249184
end
250185

251-
# Compare segment trees by their ordered values.
252-
#
253-
# @param [Tree::SegmentTree] other The segment tree to compare.
254-
# @return [Integer, nil] -1, 0, 1, or +nil+ if not comparable.
255-
def <=>(other)
256-
return nil unless other.is_a?(Tree::SegmentTree)
257-
258-
to_a <=> other.to_a
259-
end
260-
261186
private
262187

263188
# Validate the size for the tree.
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# array_tree_api_methods.rb - This file is part of the RubyTree package.
2+
#
3+
# = array_tree_api_methods.rb - Shared API helpers for array-backed trees.
4+
#
5+
# Provides shared instance-level API methods for non-TreeNode, array-backed
6+
# tree implementations.
7+
#
8+
# Author:: Anupam Sengupta (anupamsg@gmail.com)
9+
#
10+
11+
# Copyright (c) 2026 Anupam Sengupta. All rights reserved.
12+
#
13+
# Redistribution and use in source and binary forms, with or without
14+
# modification, are permitted provided that the following conditions are met:
15+
#
16+
# - Redistributions of source code must retain the above copyright notice, this
17+
# list of conditions and the following disclaimer.
18+
#
19+
# - Redistributions in binary form must reproduce the above copyright notice,
20+
# this list of conditions and the following disclaimer in the documentation
21+
# and/or other materials provided with the distribution.
22+
#
23+
# - Neither the name of the organization nor the names of its contributors may
24+
# be used to endorse or promote products derived from this software without
25+
# specific prior written permission.
26+
#
27+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
30+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
31+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
35+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37+
#
38+
# frozen_string_literal: true
39+
40+
module Tree
41+
module Utils
42+
# Shared instance-level API methods for array-backed tree types.
43+
module ArrayTreeApiMethods
44+
# Convenience synonym for +size+.
45+
#
46+
# @return [Integer] The number of elements tracked by the tree.
47+
def length
48+
size
49+
end
50+
51+
# Iterate over values in index order.
52+
#
53+
# @yieldparam value [Numeric] Value at each index.
54+
#
55+
# @return [Object] The receiver, if a block is given.
56+
# @return [Enumerator] An enumerator, if no block is given.
57+
def each(&)
58+
return to_enum(:each) unless block_given?
59+
60+
0.upto(@size - 1) { |index| yield self[index] }
61+
self
62+
end
63+
64+
# Returns all values in index order.
65+
#
66+
# @return [Array<Numeric>] Values in index order.
67+
def values
68+
to_a
69+
end
70+
71+
# Returns all indices in order.
72+
#
73+
# @return [Array<Integer>] Indices in order.
74+
def keys
75+
(0...@size).to_a
76+
end
77+
78+
# Returns all values as an Array.
79+
#
80+
# @return [Array<Numeric>] Values in index order.
81+
def to_a
82+
map { |value| value }
83+
end
84+
85+
# Returns a Hash representation of the tree.
86+
#
87+
# @return [Hash] Hash representation of the tree.
88+
def to_h
89+
{
90+
size: size,
91+
values: to_a
92+
}
93+
end
94+
95+
# JSON serialization for the tree.
96+
#
97+
# @param [Hash] _options JSON serialization options.
98+
# @return [Hash] Hash representation for JSON serialization.
99+
def as_json(_options = {})
100+
to_h
101+
end
102+
103+
# Serialize the tree to JSON.
104+
#
105+
# @param [Array] args JSON.generate arguments.
106+
# @return [String] JSON representation of the tree.
107+
def to_json(*args)
108+
JSON.generate(as_json, *args)
109+
end
110+
111+
# Compare trees by their ordered values.
112+
#
113+
# @param [Object] other The tree to compare.
114+
# @return [Integer, nil] -1, 0, 1, or +nil+ if not comparable.
115+
def <=>(other)
116+
return nil unless other.is_a?(self.class)
117+
118+
to_a <=> other.to_a
119+
end
120+
end
121+
end
122+
end

0 commit comments

Comments
 (0)