-
Notifications
You must be signed in to change notification settings - Fork 294
/
Copy pathFenwickTree.cs
106 lines (87 loc) · 2.66 KB
/
FenwickTree.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Advanced.Algorithms.DataStructures;
/// <summary>
/// A Fenwick Tree (binary indexed tree) implementation for prefix sum.
/// </summary>
public class FenwickTree<T> : IEnumerable<T>
{
private readonly T[] input;
/// <summary>
/// Add operation on generic type.
/// </summary>
private readonly Func<T, T, T> sumOperation;
private T[] tree;
/// <summary>
/// constructs a Fenwick tree using the specified sum operation function.
/// Time complexity: O(nLog(n)).
/// </summary>
public FenwickTree(T[] input, Func<T, T, T> sumOperation)
{
if (input == null || sumOperation == null) throw new ArgumentNullException();
this.input = input.Clone() as T[];
this.sumOperation = sumOperation;
Construct(input);
}
private int Length => tree.Length - 1;
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return input.Select(x => x).GetEnumerator();
}
/// <summary>
/// Construct Fenwick tree from input array.
/// </summary>
private void Construct(T[] input)
{
tree = new T[input.Length + 1];
for (var i = 0; i < input.Length; i++)
{
var j = i + 1;
while (j < input.Length)
{
tree[j] = sumOperation(tree[j], input[i]);
j = GetNextIndex(j);
}
}
}
/// <summary>
/// Gets the prefix sum from 0 till the given end index.
/// Time complexity: O(log(n)).
/// </summary>
public T PrefixSum(int endIndex)
{
if (endIndex < 0 || endIndex > Length - 1) throw new ArgumentException();
var sum = default(T);
var currentIndex = endIndex + 1;
while (currentIndex > 0)
{
sum = sumOperation(sum, tree[currentIndex]);
currentIndex = GetParentIndex(currentIndex);
}
return sum;
}
/// <summary>
/// Get index of next sibling .
/// </summary>
private int GetNextIndex(int currentIndex)
{
//add current index with
//twos complimant of currentIndex AND with currentIndex
return currentIndex + (currentIndex & -currentIndex);
}
/// <summary>
/// Get parent node index.
/// </summary>
private int GetParentIndex(int currentIndex)
{
//substract current index with
//twos complimant of currentIndex AND with currentIndex
return currentIndex - (currentIndex & -currentIndex);
}
}