Tree-like array

Source: Internet
Author: User

In an array. What would you do if you needed to calculate the amount of time in a certain interval frequently? , the simplest way is to calculate each time, but this requires O (N) time complexity, such as the demand is very frequent, then this operation will take up a lot of CPU time, further thinking, you might think of the use of space for time, the value of each interval is recorded, It is then stored in memory, reducing the complexity of Time to O (1), and indeed, for the current requirement, it has been able to meet the requirements of time complexity, despite the increase in linear spatial complexity.

But what if our source data requires frequent changes? Using the above scenario, we need a lot of updates to the interval we have saved into memory, and the effect of many of these updates is overlapping, and we need to repeat the calculations. For example, for array array[10], update the array[4] value, need to update the interval [4,5],[4,5,6], in the update [4,5,6] Need another calculation [4,5], such an update brings a lot of repeated calculations, in order to solve this problem, the tree array came into being.

You can consider using a tree array when you want to make frequent changes to the array elements, while also frequently querying the sum of any interval elements within arrays. A tree array is a very elegant data structure. Let's take a look at a picture of a tree structure.

The value of c[1] in the figure equals the value of a[1],c[2] is equal to the value of c[1]+a[2]=a[1]+a[2],c[4] =c[2]+c[3]=a[1]+a[2]+a[3]+a[4], assuming we now need to change the element a[2], Then it will only affect the elements in the C array has c[2],c[4],c[8], we just need to recalculate these values, and reduce a lot of repeated operations. This is a tree-like structure of a general storage, the following to see his definition:

Suppose A[1...N] is the original array, define C[1...N] as the corresponding tree-like array:

C[i] = a[i-2^k + 1] + A[i-2^k + 2] + ... + a[i] (where k is the binary of I that represents the number of end 0)

The following cited I by 1 ... 5 of the data, it is because the above a[i-2^k + 1]...a[i] Calculation formula to ensure the correct meaning of our C array, as for the certification process, you can read the relevant information.

Basic operation:

For the definition of C[i]=a[i-2^k + 1]...a[i], it is difficult to grind the K, his value equals I the number of binary represents the number of the end 0. If the binary representation of 4 is 0100, then K equals 2, and in fact we will find that 2^k is the weight of the former, that is, 0100, 2^2=4 is just the weight of the previous 1. So 2^k can be expressed as n& (n^ (n-1)) or simpler n& (-N), for example:

For simplicity, suppose that an int is now 4 bits and the highest bit is the sign bit

int i=3& (-3); At this point the binary of the i=1,3 is a binary of 0011,-3 1101 (negative number is the complement) so 0011&1101=1

int j=4& (-4); At this time j=4, the reason ibid.

So calculate 2^k We can use the following code:

1 int lowbit (int x)//Calculate Lowbit
2 {
3 Return x& (-X);
4}

Sum operation:

In the above, if we need to find sum[1..7] elements of the and, only need to calculate c[7]+c[6]+c[4] and can, how to calculate the complexity of the time? How many times do we have to do the summation?

Ask SUM[1..K], we need to find the binary representation of K in 1 of the number of times to get the final result, specifically why, see Code i-=lowbit (i) Comment

1 int sum (int i)//ask for the first and
2 {
3 int s=0;
4 while (i>0)
5 {
6 s+=c[i];
7 i-=lowbit (i); This step is actually equivalent to cutting the last 1 of the binary representation of I, and then the number of weights of the current 1 (example below),
8//and the binary of n has a maximum of log (n) 1, so the query efficiency is log (n)
9//On the operation can be understood to find all the child nodes in turn
10}
return s;
12}

In order to sum[1..7] For example, the binary is 0111, the right first 1 appears on the No. 0 position, that is, to start from a[7] 1 elements forward (only a[7]), that is c[7];

Then the 1 is dropped, get 6, binary representation is 0110, the right first 1 appears on the 1th position, that is, to start from a[6] 2 elements (a[6],a[5]), that is c[6];

Then the use of 1, get 4, binary representation is 0100, the right first 1 appears on the 2nd position, that is, to start from a[4] 4 elements (a[4],a[3],a[2],a[1]), that is, c[4].

So s[7]=c[7]+c[6]+c[4]

to add value to the source array operation :

In the above, assuming that the changed element is a[2], then it affects the C array of elements in the c[2],c[4],c[8], we need only one layer to the top of the modification can be, the process of the worst complexity is also O (LOGN);

void Add (int i,int val)
{
while (i<=n)
{
C[i]+=val;
I+=lowbit (i); I+ (the last 1 of the weights in the binary of I, i.e., 2^k), the operation on the top is to raise the first layer, to the previous layer of the node.
This process is actually just a process of filling the end 1 after 0 (example below)
}
}

To modify the a[2] element as an example, you need to modify the c[2],2 binary to 0010, the end of 0 is 0100, that is c[4]

4 of the binary is 0100, at the end of the 0 is 1000 is c[8]. So we need to change the c[2],c[4],c[8]

POJ above has a water problem in this area, can help to understand http://poj.org/problem?id=2352

Problem Solving Report http://hi.baidu.com/acmerskycoding/blog/item/40af1b2585dd310a4c088d95.html

In an array. What would you do if you needed to calculate the amount of time in a certain interval frequently? , the simplest way is to calculate each time, but this requires O (N) time complexity, such as the demand is very frequent, then this operation will take up a lot of CPU time, further thinking, you might think of the use of space for time, the value of each interval is recorded, It is then stored in memory, reducing the complexity of Time to O (1), and indeed, for the current requirement, it has been able to meet the requirements of time complexity, despite the increase in linear spatial complexity.

But what if our source data requires frequent changes? Using the above scenario, we need a lot of updates to the interval we have saved into memory, and the effect of many of these updates is overlapping, and we need to repeat the calculations. For example, for array array[10], update the array[4] value, need to update the interval [4,5],[4,5,6], in the update [4,5,6] Need another calculation [4,5], such an update brings a lot of repeated calculations, in order to solve this problem, the tree array came into being.

You can consider using a tree array when you want to make frequent changes to the array elements, while also frequently querying the sum of any interval elements within arrays. A tree array is a very elegant data structure. Let's take a look at a picture of a tree structure.

The value of c[1] in the figure equals the value of a[1],c[2] is equal to the value of c[1]+a[2]=a[1]+a[2],c[4] =c[2]+c[3]=a[1]+a[2]+a[3]+a[4], assuming we now need to change the element a[2], Then it will only affect the elements in the C array has c[2],c[4],c[8], we just need to recalculate these values, and reduce a lot of repeated operations. This is a tree-like structure of a general storage, the following to see his definition:

Suppose A[1...N] is the original array, define C[1...N] as the corresponding tree-like array:

C[i] = a[i-2^k + 1] + A[i-2^k + 2] + ... + a[i] (where k is the binary of I that represents the number of end 0)

The following cited I by 1 ... 5 of the data, it is because the above a[i-2^k + 1]...a[i] Calculation formula to ensure the correct meaning of our C array, as for the certification process, you can read the relevant information.

Basic operation:

For the definition of C[i]=a[i-2^k + 1]...a[i], it is difficult to grind the K, his value equals I the number of binary represents the number of the end 0. If the binary representation of 4 is 0100, then K equals 2, and in fact we will find that 2^k is the weight of the former, that is, 0100, 2^2=4 is just the weight of the previous 1. So 2^k can be expressed as n& (n^ (n-1)) or simpler n& (-N), for example:

For simplicity, suppose that an int is now 4 bits and the highest bit is the sign bit

int i=3& (-3); At this point the binary of the i=1,3 is a binary of 0011,-3 1101 (negative number is the complement) so 0011&1101=1

int j=4& (-4); At this time j=4, the reason ibid.

So calculate 2^k We can use the following code:

1 int lowbit (int x)//Calculate Lowbit
2 {
3 Return x& (-X);
4}

Sum operation:

In the above, if we need to find sum[1..7] elements of the and, only need to calculate c[7]+c[6]+c[4] and can, how to calculate the complexity of the time? How many times do we have to do the summation?

Ask SUM[1..K], we need to find the binary representation of K in 1 of the number of times to get the final result, specifically why, see Code i-=lowbit (i) Comment

1 int sum (int i)//ask for the first and
2 {
3 int s=0;
4 while (i>0)
5 {
6 s+=c[i];
7 i-=lowbit (i); This step is actually equivalent to cutting the last 1 of the binary representation of I, and then the number of weights of the current 1 (example below),
8//and the binary of n has a maximum of log (n) 1, so the query efficiency is log (n)
9//On the operation can be understood to find all the child nodes in turn
10}
return s;
12}

In order to sum[1..7] For example, the binary is 0111, the right first 1 appears on the No. 0 position, that is, to start from a[7] 1 elements forward (only a[7]), that is c[7];

Then the 1 is dropped, get 6, binary representation is 0110, the right first 1 appears on the 1th position, that is, to start from a[6] 2 elements (a[6],a[5]), that is c[6];

Then the use of 1, get 4, binary representation is 0100, the right first 1 appears on the 2nd position, that is, to start from a[4] 4 elements (a[4],a[3],a[2],a[1]), that is, c[4].

So s[7]=c[7]+c[6]+c[4]

to add value to the source array operation :

In the above, assuming that the changed element is a[2], then it affects the C array of elements in the c[2],c[4],c[8], we need only one layer to the top of the modification can be, the process of the worst complexity is also O (LOGN);

void Add (int i,int val)
{
while (i<=n)
{
C[i]+=val;
I+=lowbit (i); I+ (the last 1 of the weights in the binary of I, i.e., 2^k), the operation on the top is to raise the first layer, to the previous layer of the node.
This process is actually just a process of filling the end 1 after 0 (example below)
}
}

To modify the a[2] element as an example, you need to modify the c[2],2 binary to 0010, the end of 0 is 0100, that is c[4]

4 of the binary is 0100, at the end of the 0 is 1000 is c[8]. So we need to change the c[2],c[4],c[8]

Tree-like array

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.