5

I have seen many implementations of segment trees that use O(4*N) memory. Is there anyway for a segment tree to use exactly 2*N-1 memory? I cannot find any implementation that does this. Even if they talk about the space complexity being actually 2*N-1 they still allocate 4*N.

EDIT: What I mean is that for an array of n numbers you use an array of 2n-1 numbers for a segment tree. Every implementation uses an array of 2*(next power of 2 greater than n).

I know that the O notation omits constants but for a very large n it would matter if it is 2*N-1 or 4*N, thus the reason I asked this question.

OmG
  • 18,337
  • 10
  • 57
  • 90
Andrew
  • 1,109
  • 1
  • 15
  • 27

4 Answers4

2

As per Big O notation, O(4*N) = O(2*N-1) = O(N). Any standard implementation of segment tree uses linear memory.

Coming to your question, consider an array a[0...n-1] as input. Consider n = 10. When you construct the segment tree, it will look something like following:

Segment Tree

Number of nodes used for construction = 2*n - 1 = 19. Thus, theoretically, only 19 nodes are required!

But, we are implementing the segment tree using array data structure. Here, each node will correspond to some index in array. In segment tree, for node indexed x, left-child index = 2*x, right-child index= 2*x+1.

So, if I start with one-indexed array , index of [0, 9] = 1, [5] = 24, [6] = 25. So, you atleast need index till 25 in this case. In worst case, you will need index of 31 in case of fully grown segment tree (n=16).

Thus, we maintain the array with size 2*(next power of 2 >= n)

Rishit Sanmukhani
  • 2,159
  • 16
  • 26
1

O(4N) = O(2N) = O(N) because the O-notation does abstract from constant factors.

wikipedia Big O notation

So what do you mean by "use exactly 2N-1 memory"? Du you mean 2N-1 bytes? If you mean O(2N-1) than this is the same as O(4N), O(2*N) and O(N).

MrSmith42
  • 9,961
  • 6
  • 38
  • 49
1

You can dynamically add nodes to the tree. Then the nodes that you are not using will just not exist and won't waste memory.

0

Most people are familiar with implementing the safe 4N allocated memory which happens to be the upper bound for building a segment tree on an array of size N or the OOP version. For some idea behind this, read here. It's a very good source and has a lot of information packed on segment trees.

Now, coming to the 2N memory usage. Take a look here, here and also:

Memory efficient implementation (from here)

Most people use the implementation from the previous section. If you look at the array t you can see that it follows the numbering of the tree nodes in the order of a BFS traversal (level-order traversal). Using this traversal the children of vertex v are 2v and 2v+1 respectively. However if n is not a power of two, this method will skip some indices and leave some parts of the array t unused. The memory consumption is limited by 4n, even though a Segment Tree of an array of n elements requires only 2n−1 vertices. However it can be reduced. We renumber the vertices of the tree in the order of an Euler tour traversal (pre-order traversal), and we write all these vertices next to each other.

Lets look at a vertex at index v, and let him be responsible for the segment [l,r], and let mid=l+r2. It is obvious that the left child will have the index v+1. The left child is responsible for the segment [l,mid], i.e. in total there will be 2∗(mid−l+1)−1 vertices in the left child's subtree. Thus we can compute the index of the right child of v. The index will be v+2∗(mid−l+1). By this numbering we achieve a reduction of the necessary memory to 2n.

Arrow
  • 389
  • 2
  • 12