Content
Introduction
The segment tree is an efficient binary tree data structure where each node represents an interval, allowing range queries and dynamic updates to run in logarithmic time.
Implementation
For convenience, we consider a bounded integer array as the input and perform range sum queries on it, utilizing only a 1D discrete segment tree.
Tree (Class)
Tree definition:
1 | class SegTreeNode: |
merge
function:
1 | # merge will only be called on the parent node |
Build
The build
function runs in $O(N)$ time, where $N$ is the maximum range.
1 | # arr: input array |
Range Query
The rangeQuery
function runs in $O(log N + k)$ time, where $N$ is the maximum range and $k$ is the number of retrieved segments. As $k$ is bonunded by $4log N$, the overall time complexity is $O(log N)$.
1 | # root: the root of the segment tree |
Update
The update
functions runs in $O(log N)$ time, where $N$ is the maximum range.
1 | # root: the root of the segment tree |
Example run
1 | print("Segment Tree Implementation with class") |
1 | Segment Tree Implementation |
Pros and Cons
Pros:
- Implementing a segment tree with a tree class is much easier than the array approach (mentioned below).
- No padding is needed to make it a perfect binary tree; we only allocate the necessary tree nodes.
Cons:
- Memory inefficiency: Additional storage is required for child pointers and discrete storage. When traversing using pointers, there is a lot of random access.
Implicit Tree (Array)
This is a memory-efficient version of the segment tree implementation. We use 1-index for segment tree nodes. For a parent node with index treeIndex
, its left child has index 2*treeIndex
and its right child has index 2*treeIndex + 1
.
We will operate on a global array representing the segment tree named tree
.
Input: arr
Tree definition:
1 | tree = [0] * (4 * len(arr)) |
merge
function:
1 | # merge will only be called on the parent node |
Build
1 | # arr: input array |
Range Query
1 | # treeIndex: index into the segment tree |
Update
1 | # treeIndex: index into the segment tree |
Example run
1 | print("Segment Tree Implementation with array") |
1 | Segment Tree Implementation with array |
Pros and Cons
Pros:
- Memory efficiency: Arrays provide contiguous memory allocation, enabling faster access compared to pointer dereference.
Cons:
Padding required: The segment tree needs to be padded with zeros to ensure it forms a perfect binary tree, resulting in a size four times that of the input array.
Additional arguments needed: Extra arguments are necessary for functions such as build, rangeQuery, and update to determine the left and right boundaries of the current segment since the array itself lacks information about the segment range. Although it’s possible to encapsulate these ranges within private functions, the implementation remains more complex compared to the previous approach.