Skip to content

Commit e75d0e7

Browse files
Lakhan-Nadgithub-actionsPanquesito7
authored
Feature: Added segment_trees Closes #561 (#595)
* Feature: Added segment_trees Closes #561 * doc: documentation improved and explanations added * updating DIRECTORY.md * doc: changes in documentation * doc: suggested doc changes and int types changed * update: doc change for main function Co-authored-by: David Leal <[email protected]> Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal <[email protected]>
1 parent bb6c62a commit e75d0e7

File tree

2 files changed

+236
-0
lines changed

2 files changed

+236
-0
lines changed

DIRECTORY.md

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
* [Create Node](https://github.com/TheAlgorithms/C/blob/master/data_structures/binary_trees/create_node.c)
3333
* [Recursive Traversals](https://github.com/TheAlgorithms/C/blob/master/data_structures/binary_trees/recursive_traversals.c)
3434
* [Redblacktree](https://github.com/TheAlgorithms/C/blob/master/data_structures/binary_trees/redblacktree.c)
35+
* [Segment Tree](https://github.com/TheAlgorithms/C/blob/master/data_structures/binary_trees/segment_tree.c)
3536
* [Threaded Binary Trees](https://github.com/TheAlgorithms/C/blob/master/data_structures/binary_trees/threaded_binary_trees.c)
3637
* Dictionary
3738
* [Dict](https://github.com/TheAlgorithms/C/blob/master/data_structures/dictionary/dict.c)
+235
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
/**
2+
* @file segment_tree.c
3+
* @brief segment trees with only point updates
4+
* @details
5+
* This code implements segment trees. Segment trees are general structures
6+
* which allow range based queries in a given array in logN time.
7+
* Segment tree with point updates allow update of single element in the array
8+
* in logN time.
9+
* [Learn more about segment trees
10+
* here](https://codeforces.com/blog/entry/18051)
11+
* @author [Lakhan Nad](https://github.com/Lakhan-Nad)
12+
*/
13+
14+
#include <assert.h> /* for assert */
15+
#include <inttypes.h> /* for int32 */
16+
#include <stdio.h> /* for scanf printf */
17+
#include <stdlib.h> /* for malloc, free */
18+
#include <string.h> /* for memcpy, memset */
19+
20+
/**
21+
* Function that combines two data to generate a new one
22+
* The name of function might be misleading actually combine here signifies the
23+
* fact that in segment trees we take partial result from two ranges and using
24+
* partial results we derive the result for joint range of those two ranges
25+
* For Example: array(1,2,3,4,5,6) sum of range [0,2] = 6
26+
* and sum of range [3,5] = 15 the combined sum of two range is 6+15=21
27+
* @note The function is same to binary function in Discrete Mathematics
28+
* @param a pointer to first data
29+
* @param b pointer to second data
30+
* @param result pointer to memory location where result of combining a and b is
31+
* to be stored
32+
*/
33+
typedef void (*combine_function)(const void *a, const void *b, void *result);
34+
35+
/**
36+
* This structures holds all the data that is required by a segment tree
37+
*/
38+
typedef struct segment_tree
39+
{
40+
void *root; /**< the root of formed segment tree */
41+
void *identity; /**< identity element for combine function */
42+
size_t elem_size; /**< size in bytes of each data element */
43+
size_t length; /**< total size of array which segment tree represents*/
44+
/** the function to be used to combine two node's
45+
* data to form parent's data
46+
*/
47+
combine_function combine;
48+
} segment_tree;
49+
50+
/**
51+
* Builds a Segment tree
52+
* It is assumed that leaves of tree already contains data.
53+
* @param tree pointer to segment tree to be build
54+
*/
55+
void segment_tree_build(segment_tree *tree)
56+
{
57+
size_t elem_size = tree->elem_size;
58+
int index = (tree->length - 2);
59+
size_t b, l, r;
60+
char *ptr = (char *)tree->root;
61+
for (; index >= 0; index--)
62+
{
63+
b = index * elem_size;
64+
l = (2 * index + 1) * elem_size;
65+
r = (2 * index + 2) * elem_size;
66+
tree->combine(ptr + l, ptr + r, ptr + b);
67+
}
68+
}
69+
70+
/**
71+
* For point updates
72+
* This function updates the element at given index and also updates segment
73+
* tree accordingly
74+
*
75+
* @param tree pointer to segment tree
76+
* @param index the index whose element is to be updated (0 based indexing used)
77+
* @param val pointer to value that is to be replaced at given index
78+
*/
79+
void segment_tree_update(segment_tree *tree, size_t index, void *val)
80+
{
81+
size_t elem_size = tree->elem_size;
82+
index = index + tree->length - 1;
83+
char *base = (char *)tree->root;
84+
char *t = base + index * elem_size;
85+
memcpy(t, val, elem_size);
86+
while (index > 0)
87+
{
88+
index = ((index - 1) >> 1);
89+
tree->combine(base + (2 * index + 1) * elem_size,
90+
base + (2 * index + 2) * elem_size,
91+
base + index * elem_size);
92+
}
93+
}
94+
95+
/**
96+
* Query the segment tree
97+
* This function helps in range query of segment tree
98+
* This function assumes that the given range is valid
99+
* Performs the query in range [l,r]
100+
* @param tree pointer to segment tree
101+
* @param l the start of range
102+
* @param r the end of range
103+
* @param res the pointer to memory where result of query is stored
104+
*/
105+
void segment_tree_query(segment_tree *tree, long long l, long long r, void *res)
106+
{
107+
size_t elem_size = tree->elem_size;
108+
memcpy(res, tree->identity, elem_size);
109+
elem_size = tree->elem_size;
110+
char *root = (char *)tree->root;
111+
l += tree->length - 1;
112+
r += tree->length - 1;
113+
while (l <= r)
114+
{
115+
if (!(l & 1))
116+
{
117+
tree->combine(res, root + l * elem_size, res);
118+
}
119+
if (r & 1)
120+
{
121+
tree->combine(res, root + r * elem_size, res);
122+
}
123+
r = (r >> 1) - 1;
124+
l = (l >> 1);
125+
}
126+
}
127+
128+
/**
129+
* Initializes Segment Tree
130+
* Accquires memory for segment tree
131+
* and fill the leaves of segment tree with data from array
132+
* @param arr the array data upon which segment tree is build
133+
* @param elem_size size of each element in segment tree
134+
* @param len total no of elements in array
135+
* @param identity the identity element for combine_function
136+
* @param func the combine_function used to build segment tree
137+
*
138+
* @returns pointer to sgement tree build
139+
*/
140+
segment_tree *segment_tree_init(void *arr, size_t elem_size, size_t len,
141+
void *identity, combine_function func)
142+
{
143+
segment_tree *tree = malloc(sizeof(segment_tree));
144+
tree->elem_size = elem_size;
145+
tree->length = len;
146+
tree->combine = func;
147+
tree->root = malloc(sizeof(char) * elem_size * (2 * len - 1));
148+
tree->identity = malloc(sizeof(char) * elem_size);
149+
char *ptr = (char *)tree->root;
150+
memset(ptr, 0, (len - 1) * elem_size); // Initializing memory
151+
ptr = ptr + (len - 1) * elem_size;
152+
memcpy(ptr, arr, elem_size * len); // copy the leaf nodes i.e. array data
153+
memcpy(tree->identity, identity, elem_size); // copy identity element
154+
return tree;
155+
}
156+
157+
/**
158+
* Dispose Segment Tree
159+
* Frees all heap memory accquired by segment tree
160+
* @param tree pointer to segment tree
161+
*/
162+
void segment_tree_dispose(segment_tree *tree)
163+
{
164+
free(tree->root);
165+
free(tree->identity);
166+
}
167+
168+
/**
169+
* Prints the data in segment tree
170+
* The data should be of int type
171+
* A utility to print segment tree
172+
* with data type of int
173+
* @param tree pointer to segment tree
174+
*/
175+
void segment_tree_print_int(segment_tree *tree)
176+
{
177+
char *base = (char *)tree->root;
178+
size_t i = 0;
179+
for (; i < 2 * tree->length - 1; i++)
180+
{
181+
printf("%d ", *(int *)(base + i * tree->elem_size));
182+
}
183+
printf("\n");
184+
}
185+
186+
/**
187+
* Utility for test
188+
* A function compare for minimum between two integers
189+
* This function is used as combine_function for RMQ
190+
* @param a pointer to integer a
191+
* @param b pointer to integer b
192+
* @param c pointer where minimum of a and b is tored as result
193+
*/
194+
void minimum(const void *a, const void *b, void *c)
195+
{
196+
*(int *)c = *(int *)a < *(int *)b ? *(int *)a : *(int *)b;
197+
}
198+
199+
/**
200+
* Test RMQ
201+
* Testing Segment tree using
202+
* Range Minimum Queries
203+
* @returns void
204+
*/
205+
static void test()
206+
{
207+
int32_t arr[10] = {1, 0, 3, 5, 7, 2, 11, 6, -2, 8};
208+
int32_t identity = __INT32_MAX__;
209+
segment_tree *tree =
210+
segment_tree_init(arr, sizeof(*arr), 10, &identity, minimum);
211+
segment_tree_build(tree);
212+
int32_t result;
213+
segment_tree_query(tree, 3, 6, &result);
214+
assert(result == 2);
215+
segment_tree_query(tree, 8, 9, &result);
216+
assert(result == -2);
217+
result = 12;
218+
segment_tree_update(tree, 5, &result);
219+
segment_tree_update(tree, 8, &result);
220+
segment_tree_query(tree, 0, 3, &result);
221+
assert(result == 0);
222+
segment_tree_query(tree, 8, 9, &result);
223+
assert(result == 8);
224+
segment_tree_dispose(tree);
225+
}
226+
227+
/**
228+
* @brief Main Function
229+
* @returns 0 on exit
230+
*/
231+
int main()
232+
{
233+
test();
234+
return 0;
235+
}

0 commit comments

Comments
 (0)