Skip to content

Commit

Permalink
Added implementation of fenwick tree (keon#739)
Browse files Browse the repository at this point in the history
* Added implementation of fenwick tree in the tree folder

* Converted into data structure and removed main function. Created a new directory in the tree directory to store the python file.

* Converted into data structure and removed main function. Created a new directory in the tree directory to store the python file.

* Converted into data structure and removed main function. Created a new directory in the tree directory to store the python file.
  • Loading branch information
ShimoniSinha2019H1030019G authored Nov 6, 2020
1 parent 9b320bf commit 8ebe8b5
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ If you want to uninstall algorithms, it is as simple as:
- [count_left_node](algorithms/tree/bst/count_left_node.py)
- [num_empty](algorithms/tree/bst/num_empty.py)
- [height](algorithms/tree/bst/height.py)
- [fenwick_tree](algorithms/tree/fenwick_tree]
- [fenwick_tree](algorithms/tree/fenwick_tree/fenwick_tree.py)
- [red_black_tree](algorithms/tree/red_black_tree)
- [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py)
- [segment_tree](algorithms/tree/segment_tree)
Expand Down
77 changes: 77 additions & 0 deletions algorithms/tree/fenwick_tree/fenwick_tree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""
Fenwick Tree / Binary Indexed Tree
Consider we have an array arr[0 . . . n-1]. We would like to
1. Compute the sum of the first i elements.
2. Modify the value of a specified element of the array arr[i] = x where 0 <= i <= n-1.
A simple solution is to run a loop from 0 to i-1 and calculate the sum of the elements. To update a value, simply do arr[i] = x.
The first operation takes O(n) time and the second operation takes O(1) time.
Another simple solution is to create an extra array and store the sum of the first i-th elements at the i-th index in this new array.
The sum of a given range can now be calculated in O(1) time, but the update operation takes O(n) time now.
This works well if there are a large number of query operations but a very few number of update operations.
There are two solutions that can perform both the query and update operations in O(logn) time.
1. Fenwick Tree
2. Segment Tree
Compared with Segment Tree, Binary Indexed Tree requires less space and is easier to implement.
"""

class Fenwick_Tree(object):
def __init__(self, freq):
self.arr = freq
self.n = len(freq)

def get_sum(self, bit_tree, i):
"""
Returns sum of arr[0..index]. This function assumes that the array is preprocessed and partial sums of array elements are stored in bit_tree[].
"""

s = 0

# index in bit_tree[] is 1 more than the index in arr[]
i = i+1

# Traverse ancestors of bit_tree[index]
while i > 0:

# Add current element of bit_tree to sum
s += bit_tree[i]

# Move index to parent node in getSum View
i -= i & (-i)
return s

def update_bit(self, bit_tree, i, v):
"""
Updates a node in Binary Index Tree (bit_tree) at given index in bit_tree. The given value 'val' is added to bit_tree[i] and all of its ancestors in tree.
"""

# index in bit_ree[] is 1 more than the index in arr[]
i += 1

# Traverse all ancestors and add 'val'
while i <= self.n:

# Add 'val' to current node of bit_tree
bit_tree[i] += v

# Update index to that of parent in update View
i += i & (-i)


def construct(self):
"""
Constructs and returns a Binary Indexed Tree for given array of size n.
"""

# Create and initialize bit_ree[] as 0
bit_tree = [0]*(self.n+1)

# Store the actual values in bit_ree[] using update()
for i in range(self.n):
self.update_bit(bit_tree, i, self.arr[i])

return bit_tree
Empty file removed tests/__init__.py
Empty file.
32 changes: 32 additions & 0 deletions tests/test_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

from algorithms.tree import construct_tree_postorder_preorder as ctpp

from algorithms.tree.fenwick_tree.fenwick_tree import Fenwick_Tree

import unittest


Expand Down Expand Up @@ -137,6 +139,36 @@ def test_construct_tree(self):
self.assertEqual(ctpp.construct_tree(pre3, post3, size3), [16,7,21,12,1,5,9])


class TestFenwickTree(unittest.TestCase):
def test_construct_tree_with_update_1(self):
freq = [2, 1, 1, 3, 2, 3, 4, 5, 6, 7, 8, 9]
ft = Fenwick_Tree(freq)
bit_tree = ft.construct()
self.assertEqual(12, ft.get_sum(bit_tree, 5))

freq[3] += 6
ft.update_bit(bit_tree, 3, 6)
self.assertEqual(18, ft.get_sum(bit_tree, 5))

def test_construct_tree_with_update_2(self):
freq = [1, 2, 3, 4, 5]
ft = Fenwick_Tree(freq)
bit_tree = ft.construct()
self.assertEqual(10, ft.get_sum(bit_tree, 3))

freq[3] -= 5
ft.update_bit(bit_tree, 3, -5)
self.assertEqual(5, ft.get_sum(bit_tree, 3))

def test_construct_tree_with_update_3(self):
freq = [2, 1, 4, 6, -1, 5, -32, 0, 1]
ft = Fenwick_Tree(freq)
bit_tree = ft.construct()
self.assertEqual(12, ft.get_sum(bit_tree, 4))

freq[2] += 11
ft.update_bit(bit_tree, 2, 11)
self.assertEqual(23, ft.get_sum(bit_tree, 4))

if __name__ == '__main__':
unittest.main()

0 comments on commit 8ebe8b5

Please sign in to comment.