package arithmetic; import java.util.*; public class TreeArray { public static int[] conver(int array[]) { int tree[] = new int[array.length]; Arrays.fill(tree,0); for(int i=1;i<=array.length;i++) for(int j=i;j>=(i-lowbit(i)+1);j--) //也可以写成for(int j=i;j>i-lowbit(i);j--) tree[i-1]+=array[j-1]; return tree; } public static int lowbit(int x) // 求 2^k { return x&(x^(x-1)); } /* * 数状数组的应用- * 求一个数组的前N 项各 Sum(array,n); * * */ public static int arraySum(int []array,int n) { int sum=0; int tree[] = conver(array); //求出该数组的数状数组 while(n>=0) { sum+=tree[n]; //tree[n] 表示从array[n] 到 array[lowbit(n+1)]项的和 n-=lowbit(n+1); //因为数组数组的 索引是从0开始的,所以这里要加1 } return sum; } /* * 数状数组应用二 * 对原数组修改,其数组数组对应也要做出修改 * */ public static int [] add(int []array,int n,int data)//将array 数组中的第n 个元素加上data 后,求出其数组状数组 { int tree[] = conver(array); while(n<=array.length) { tree[n]+=data; n+=lowbit(n+1); //只要改变其上一级相关的值(之所以加1 就因为数头数组的索引是从0开始的),弄清数组数组中结点与上级结点之间的关系 //因为你只改变了一个结点,其上级结点也要改变 tree[n] 的上级结点为 tree[n+lowbit(n)] } return tree; } public static void main(String args[]) { int array[]= {1,2,3,4,5,6,7,8}; System.out.println(Arrays.toString(conver(array))); int tree[] = add(array,0,1); System.out.println(Arrays.toString(tree)); } } /* * * 数状数组 * 有一个数组 Array={1,2,3,4,5,6,7,8}; * 用一个树的结点来表示这个数组内某几项的和,而树的结点是有规律的 * * C[] 表示该树的结点的序号 * C[n] =Array[n-2^k+1]+.....+Array[n]; (2^k 表示2的K次方,K是表示N的二进制位末尾0的个数,有一个公式来计算 2^k) * 那就是 n&(n^(n-1)) 中期的^ 表示异或 * 所以上面的公式也就是 C[n] = Array[n-n&(n^(n-1)]+.....+Array[n]; * * * * 在操作数组与数状数组之间的关系时,要弄清两点 * 1. 数状数组中,结点与其上级结点的关系。因为你要修改,一个结点的改变,其相连的上级结点也要改变 tree[n] 上级结点 tree[n+lowbit(n)] * 2. 弄清数状数组中结点与其数组中结点的关系。数组数组中的一个结点是数组中一个多个连接的结点的和 tree[n]=array[n-lowbit(n)+1]+.....+array[n] * * 参考: * http://dongxicheng.org/structure/binary_indexed_tree/ * http://old.blog.edu.cn/user3/Newpoo/archives/2007/1712628.shtml * * */