Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
73a4090
Removed debug changes
czgdp1807 Dec 31, 2021
18f922e
Merge branch 'master' of https://github.com/codezonediitj/pydatastructs
czgdp1807 Dec 31, 2021
b10328a
Merge branch 'master' of https://github.com/codezonediitj/pydatastructs
czgdp1807 Jan 30, 2022
224a314
Merge branch 'master' of https://github.com/codezonediitj/pydatastructs
czgdp1807 Feb 6, 2022
1869ccc
Initial Test Commit
Feb 22, 2022
a4a7040
Added Segment Trees with Lazy Propagation
Feb 26, 2022
1cc6aa3
Added DocStrings and necessary use cases and examples for the data st…
Mar 4, 2022
42d9214
Delete AUTHORS
Rajveer100 Mar 4, 2022
c68e242
Delete segmentTree.py
Rajveer100 Mar 4, 2022
4d463c0
Reverted Deleted Authors tile
Mar 4, 2022
0f1dad1
Added tests for Segment Tree
Mar 5, 2022
88c5363
Fixed Code Patterns as per repo...
Mar 8, 2022
bf6437f
Updated Tests with addition of Static Tests.
Mar 8, 2022
6316186
Corrected header file directory...
Mar 9, 2022
4183f05
Further corrections in import...
Mar 9, 2022
03db406
Fixed White Space Issue...
Mar 9, 2022
a324843
New Line Issue..Fixed
Mar 9, 2022
0434e5c
Merge branch 'master' of https://github.com/codezonediitj/pydatastructs
czgdp1807 Mar 13, 2022
b042d18
Merge branch 'master' into origin_user
czgdp1807 Mar 13, 2022
04561d3
build method added for ArraySegmentTree interface
czgdp1807 Mar 13, 2022
59643a3
Added update method for ArraySegmentTree
czgdp1807 Mar 13, 2022
33d14b9
Added query method to ArraySegmentTree
czgdp1807 Mar 13, 2022
0c9d736
Removed test_segment_trees.py
czgdp1807 Mar 13, 2022
327db49
Fixed code quality tests
czgdp1807 Mar 13, 2022
0e9e1a7
Added RangeQueryDynamic and Tests
czgdp1807 Mar 20, 2022
dd98e81
Tested
czgdp1807 Mar 20, 2022
551e58d
Added doctest
czgdp1807 Mar 20, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions AUTHORS

This file was deleted.

241 changes: 241 additions & 0 deletions pydatastructs/miscellaneous_data_structures/segment_tree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
class SegmentTree :

"""
Represents the Segment Tree Data Structure

Functions :

-- Use case with example of all functions (including internal)
is specified below each of their respective declarations --

-- All Internal functions required to maintain the Segment Tree are represented as __[function_name]__

-------------------------------------------------------------------------------------------------------------

Range Query => Returns the respective query(sum, min, gcd ...) in the range [L, R]
as specified in the function parameter.

Point Update => Updates the element value at the specified position [pos] by replacing
it with the new value [newVal], thereby updating the tree.

Range Update => Adds new value [newVal] to each of the elements in the range [L, R] ensuring
the required updates using lazy propagation

-------------------------------------------------------------------------------------------------------------

Time Complexity : Each of the above functions of the tree is performed in O(log(N)), due to the height
of the tree being log(N).

Space Complexity : The size of the main tree [tree] and the lazy tree [lazy] both consume O(2*N) memory
to represent each of the 2 * N - 1 nodes in the tree.

-------------------------------------------------------------------------------------------------------------


"""

"""
Represents the default constructor call with the initial [list]
being the parameter in order to build the tree.
"""

def __init__(self, _list_) :

"""
-- Returns the closest power of 2 from the [size] of
the initial [list]. --

-- The return value of this function will be the size of the segment tree [tree] as well as the
lazy tree [lazy] there by having 2 * [returned size] as the size of the array. --

Example :

-- Let the list size be 19, then the closest power would be 32. --
-- Hence, the new size of the tree would be 32 before the build function is called --
"""

def __getLen__(_size_) :

if _size_ and _size_ & (_size_ - 1) == 0 :

return _size_
else :

_bitLen_ = len(bin(_size_)) - 2
return 1 << _bitLen_

self._treeSize_ = 2 * __getLen__(len(_list_))

self._tree_ = [0 for i in range(self._treeSize_)]
self._lazy_ = [0 for i in range(self._treeSize_)]

"""
-- Performs the build procedure for the tree
to initialize the tree with the respective values in each of the 2 * N nodes. --

Example :

-- General Representation of the Tree --

|1|
|2| |3|
|4| |5| |6| |7|
|8| |9| |10| |11| |12| |13| |14| |15|

-- In the above example tree, the nodes 8...15 would store the initial [list] with additional nodes storing
appropriate dummy values [ex: For sum => 0, For min => inf, etc.]. --

-- Each of the parent nodes would then be updated by traversing in a bottom-up manner. --
"""

def __build__(_list_) :

_listSize_ = len(_list_)

for i in range(_listSize_) :

self._tree_[self._treeSize_ // 2 + i] = _list_[i]

for i in range(_listSize_, self._treeSize_ // 2) :

self._tree_[self._treeSize_ // 2 + i] = 0

for i in range(self._treeSize_ // 2 - 1, 0, -1) :

self._tree_[i] = self._tree_[2 * i] + self._tree_[2 * i + 1]

self._root_ = self._tree_[1]

__build__(_list_)

"""

Returns the query value for the specified range [L, R] for a particular [node].

[Internally called by the rangeQuery(l, r) function]
"""

def __rangeQuery__(self, _node_, _treeLeft_, _treeRight_, _left_, _right_) :

if self._lazy_[_node_] :

self._tree_[_node_] += self._lazy_[_node_] * (_treeRight_ - _treeLeft_ + 1)

if _treeLeft_ != _treeRight_ :

self._lazy_[2 * _node_] += self._lazy_[_node_]
self._lazy_[2 * _node_ + 1] += self._lazy_[_node_]

self._lazy_[_node_] = 0

if _treeLeft_ >= _left_ and _treeRight_ <= _right_ :

return self._tree_[_node_]

elif _treeLeft_ > _right_ or _treeRight_ < _left_ :

return 0

else :

_mid_ = (_treeLeft_ + _treeRight_) // 2

return \
self.__rangeQuery__(2 * _node_, _treeLeft_, _mid_, _left_, _right_) + \
self.__rangeQuery__(2 * _node_ + 1, _mid_ + 1, _treeRight_, _left_, _right_)

"""
Updates the tree accordingly for the specified range [L, R] for a particular [node] and [newVal].

[Internally called by the rangeUpdate(l, r) function]
"""

def __rangeUpdate__(self, _node_, _treeLeft_, _treeRight_, _left_, _right_, _newVal_) :

if self._lazy_[_node_] :

self._tree_[_node_] += self._lazy_[_node_] * (_treeRight_ - _treeLeft_ + 1)

if _treeLeft_ != _treeRight_ :

self._lazy_[2 * _node_] += self._lazy_[_node_]
self._lazy_[2 * _node_ + 1] += self._lazy_[_node_]

self._lazy_[_node_] = 0

if _treeLeft_ >= _left_ and _treeRight_ <= _right_ :

self._tree_[_node_] += _newVal_ * (_treeRight_ - _treeLeft_ + 1)

if _treeLeft_ != _treeRight_ :

self._lazy_[2 * _node_] += _newVal_
self._lazy_[2 * _node_ + 1] += _newVal_

elif _treeLeft_ > _right_ or _treeRight_ < _left_ :

return

else :

_mid_ = (_treeLeft_ + _treeRight_) // 2

self.__rangeUpdate__(2 * _node_, _treeLeft_, _mid_, _left_, _right_, _newVal_)
self.__rangeUpdate__(2 * _node_ + 1, _mid_ + 1, _treeRight_, _left_, _right_, _newVal_)

self._tree_[_node_] = self._tree_[2 * _node_] + self._tree_[2 * _node_ + 1]

"""
Updates the tree accordingly for the specified position [pos] with the [newVal].

[Internally called by the pointUpdate(l, r) function]
"""

def __pointUpdate__(self, _pos_, _newVal_) :

self._tree_[self._treeSize_ // 2 + _pos_] = _newVal_

_node_ = (self._treeSize_ // 2 + _pos_) // 2

while _node_ >= 1 :

self._tree_[_node_] = self._tree_[2 * _node_] + self._tree_[2 * _node_ + 1]
_node_ //= 2

"""
-- All functions below are the User Functions which invoke the necessary
Internal Functions as mentioned earlier. --
"""

def rangeUpdate(self, _left_, _right_, _newVal_) :

self.__rangeUpdate__(1, 0, self._treeSize_ // 2 - 1, _left_, _right_, _newVal_)

def pointUpdate(self, _pos_, _newVal_) :

self.__pointUpdate__(_pos_, _newVal_)

def rangeQuery(self, _left_, _right_) :

return self.__rangeQuery__(1, 0, self._treeSize_ // 2 - 1, _left_, _right_)

"""
Example for using the SegmentTree class (with testcase) :

a = [3, 5, 4, 8, 1, 4] => List of elements.
tree = SegmentTree(a) => New object of class Segment Tree by passing the list.

print(tree.rangeQuery(2, 4)) => Sum of [2, 4] = 13

[Let's say we want to update the element at position 3 with the value 18]

tree.pointUpdate(3, 18)

print(tree.rangeQuery(2, 5)) => Sum of [2, 5] = 27

[Let's say we want to add 9 to elements in the range [0, 2]]

tree.rangeUpdate(0, 2, 9)

print(tree.rangeQuery(0, 4) => Sum of [0, 4] = 58
"""