Understanding tree Arrays Using Binary Trees

Source: Internet
Author: User

A tree array (Fenwick tree, also known as binary indexed tree) is a very useful data structure. It uses node I to record all the numbers of the array subscripts in the range [I-2 ^ k + 1, I] (where, k is the number of zeros at the end of the binary representation of I. lowbit (I) = 2 ^ k) is set to search for and update the array data within the O (lg n) time.

The traditional interpretation graph of the tree array cannot intuitively see the update and query operations it can perform. Its primary operation function lowbit (k) is related to the binary representation of the number, which is essentially a binary classification. Therefore, binary trees can be used for analysis. In fact, from the binary tree graph, we can perform and cannot perform operations on it at a glance.

Similar to the dot tree mentioned above, first draw a binary tree and then traverse the node in order (the dot tree uses the breadth first). Each node still records only the information of the Left subtree, as shown in the figure below:


Because the central traversal is used, k leaves are counted from node 1 to node k.

Proof:

The leaf k must be under the left Tree of node k.

Tree with node k as the root, and its left subtree has a total of leaf lowbit (k)

The parent node of node k is k + lowbit (k) or k-lowbit (k)

Node k + lowbit (k) is the nearest parent node of node k, and node k is under its left subtree.

Node k-lowbit (k) is the nearest parent node of node k, and node k is under its right subtree.

Node k. The statistical leaf range is: (k-lowbit (k), k].

The left child of node k is k-lowbit (k)/2.

 

The main applications of the tree array are as follows:

1. Update Data x for Interval query.

2. Update the interval to query a certain number.

Because tree arrays only count the information of the Left subtree, they can only query the update range [1, x]. The interval [x, y] can be performed only when the information meeting [x, y] can be deduced by the information of [1, x-1] and [1, y, y. This is also the root cause why tree arrays cannot be used to obtain the maximum value in any interval.

 

Define two sets first:

Up_right (k): All the parent nodes of node k, and node k is under their left Tree.

Up_left (k): All the parent nodes of node k, and node k is under their right tree.

 

1. Update Data x and query interval [1, y].

Apparently, to update leaf x, we need to find out which nodes of leaf x are located under the left Tree. Therefore, node k and all up_right (k)

Must be updated.

When querying [1, y], you actually split the interval into a series of cells and find the nodes that count These intervals. By finding out which nodes of y are under the right tree, these nodes happen not to repeat the statistical interval [1, Y-1]. Therefore, you need to access node y and all up_left (y ).

 

2. Update the interval [1, y] and query data x.

This is the opposite of the previous operation. The biggest difference from the previous one is that a node no longer stores the information about the total number of its leaves, but how many leaves have changed in the interval. That is to say, the information of each leaf is distributed to all nodes for statistics. Therefore, the operation is similar to the previous one:

When updating [1, y], update node y and all up_left (y ).

When querying x, access x and all up_right (x ).

 

In the preceding tree array, only the left subtree information is counted. If the tree array is initialized from the back to the back, the tree array is counted only for the right subtree information. In this case, the update and query operations are performed, the opposite is true.

 

Generally, the tree array saves space than the Vertex Tree. For the interval [1, M], as long as the space is M + 1, the positioning node is faster when the query is updated, locating the parent node and the left and right children is relatively troublesome (however, it is generally not necessary. For more information, see the erease_nth function in the following code (delete the nth small number )).

 

The following is the implementation code using a tree array (calculate the inverse ordinal number and simulate the Joseph Ring problem ):

 

 

Tree Array
// Www.cnblogs.com/flyinghearts
# Include <cstdio>
# Include <cstring>
# Include <cassert>
 
Template <int N> struct Round2k
{Enum {down = Round2k <N/2u>: down * 2 };};

Template <> struct Round2k <1 >{ enum {down = 1 };};
 

Template <int Total, typename T = int> // interval [1, Total]
Class BIT {
Enum {Min2k = Round2k <Total >:: down };
T info [Total + 1];
T sz; // you can use info [0] to store the total size.

Public:
BIT () {clear ();}
Void clear () {memset (this, 0, sizeof (* this ));}
Int size () {return sz ;}

Int lowbit (int idx) {return idx &-idx ;}
// Find the nearest parent node. left_up/right_up respectively make idx under its right/left Tree
Void left_up (int & idx) {idx-= lowbit (idx );}
Void right_up (int & idx) {idx + = lowbit (idx );}

Void update (int idx, const int val = 1) {// change the val count of the leaf idx.
Assert (idx> 0 );
Sz + = val;
For (; idx <= Total; right_up (idx) info [idx] + = val;
}

Void init (int arr [], int n) {// arr [I] indicates the number of leaf I + 1
Assert (n <= Total );
Sz = n;
// For (int I = 0; I <n ;){
// Info [I + 1] = arr [I];
// If (++ I> = n) break;
// Info [I + 1] = arr [I];
// ++ I;
// For (int j = 1; j <lowbit (I); j * = 2u) info [I] + = info [I-j];
//}
For (int I = 0; I <n ;){
Info [I + 1] = arr [I];
If (++ I> = n) break;
Int sum = arr [I];
Int pr = ++ I;
Left_up (pr );
For (int j = I-1; j> pr; left_up (j) sum + = info [j];
Info [I] = sum;
}
}

Int count (int idx) {// [1, idx]-[1, idx-1]
Assert (idx> 0 );
Int sum = info [idx];
// Int pr = idx; // int pr = idx-lowbit (idx );
// Left_up (pr );
// For (-- idx; idx> pr; left_up (idx) sum-= info [idx]; //
// Return sum;
For (int j = 1; j <lowbit (idx); j * = 2u) sum-= info [idx-j];
Return sum;
}

Int lteq (int idx) {// small equals
Assert (idx> = 1 & idx <= Total );
Int sum = 0;
For (; idx> 0; left_up (idx) sum + = info [idx];
Return sum;
}

Int gt (int idx) {return sz-lteq (idx);} // greater

Int operator [] (int n) {return erase_nth (n, 0);} // small n

Int erase_nth (int n, const bool erase_flag = true) // Delete the nth small number
{
Assert (n> = 1 & n <= sz );
Sz-= erase_flag;
Int idx = Min2k; // search from top to bottom, first locate the root node
For (int k = idx/2u; k> 0; k/= 2u ){
Int t = info [idx];
If (n <= info [idx]) {info [idx]-= erase_flag; idx-= k;} // enter the left subtree
Else {
N-= t;
If (Total! = Min2k & Total! = Min2k-1) // if it is not a complete Binary Tree
While (idx + k> Total)

Related Article

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.