Skip to content

Commit d49aade

Browse files
Add Fenwick regression doctests and 2000-item benchmark
Preserve all existing doctests while covering lost range maxima and decreases. Add an optional timeit benchmark for update and query workloads, as requested in #15485.
1 parent da62526 commit d49aade

1 file changed

Lines changed: 56 additions & 0 deletions

File tree

‎data_structures/binary_tree/maximum_fenwick_tree.py‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,26 @@ class MaxFenwickTree:
3434
>>> ft.update(0, 1000)
3535
>>> ft.query(0, 1)
3636
1000
37+
38+
Updating a smaller sibling preserves the maximum, including after decreases.
39+
>>> ft = MaxFenwickTree(8)
40+
>>> ft.update(4, 20)
41+
>>> ft.update(5, 1)
42+
>>> ft.query(0, 6)
43+
20
44+
>>> ft.update(4, 0)
45+
>>> ft.query(0, 6)
46+
1
47+
>>> ft.update(5, 0)
48+
>>> ft.query(0, 6)
49+
0
50+
51+
Updating a child must also preserve the ancestor's own array value.
52+
>>> ft = MaxFenwickTree(8)
53+
>>> ft.update(5, 100)
54+
>>> ft.update(4, 0)
55+
>>> ft.query(0, 6)
56+
100
3757
"""
3858

3959
def __init__(self, size: int) -> None:
@@ -112,5 +132,41 @@ def query(self, left: int, right: int) -> int:
112132

113133
if __name__ == "__main__":
114134
import doctest
135+
import sys
136+
from timeit import repeat
115137

116138
doctest.testmod()
139+
140+
# Run with --benchmark on each revision to compare the same 2,000-item workload.
141+
if "--benchmark" in sys.argv:
142+
size = 2000
143+
values = [(index * 97) % size for index in range(size)]
144+
updates = [(index, (index * 37) % size) for index in range(size)]
145+
updates += [(index, values[index]) for index in reversed(range(size))]
146+
queries = [(left, size) for left in range(size)]
147+
148+
# Build correct query buckets outside the timer, even on the buggy revision.
149+
query_setup = """
150+
tree = MaxFenwickTree(size)
151+
tree.arr = values[:]
152+
tree.tree = [
153+
max(values[tree.get_prev(index) + 1 : index + 1])
154+
for index in range(size)
155+
]
156+
"""
157+
for operation, statement, setup in (
158+
(
159+
"4000 updates",
160+
"for index, value in updates: tree.update(index, value)",
161+
"tree = MaxFenwickTree(size)",
162+
),
163+
(
164+
"2000 queries",
165+
"for left, right in queries: tree.query(left, right)",
166+
query_setup,
167+
),
168+
):
169+
timings = repeat(
170+
statement, setup=setup, repeat=5, number=1, globals=globals()
171+
)
172+
print(f"{size} items, {operation}: {min(timings):.6f} seconds (best of 5)")

0 commit comments

Comments
 (0)