樹狀數組

樹狀數組(Binary Indexed Tree(B.I.T), Fenwick Tree)是一個查詢和修改複雜度都爲log(n)的數據結構,空間複雜度則爲O(n),通過將線性結構轉化成樹狀結構,從而進行跳躍式掃描。主要用於查詢任意兩位之間的所有元素之和,但是每次只能修改一個元素的值;經過簡單修改可以在log(n)的複雜度下進行範圍修改,但是這時只能查詢其中一個元素的值(如果加入多個輔助數組則可以實現區間修改與區間查詢)。


A數組是原數組,c數組是樹狀數組,可以發現:

C1 = A1
C2 = A1+A2
C3 = A3
C4 = A1+A2+A3+A4
C5 = A5
C6 = A5+A6
C7 = A7

C8 = A1+A2+A3+A4+A5+A6+A7+A8

對任意n ,C[n]=A[n-2^k+1]+……A[n],k爲n在二進制下末尾0的個數,例如n=6(110),k=1.

  • Lowbit:

用函數Lowbit(x)可以求出2^k:

int Lowbit(int x)
{
	return x&(-x);    //或return x&(x^(x-1));
}

這裏x&(-x)利用了機器補碼的特性。

  • 區間查詢

sum(a,b)=sum(1,b)-sum(1,a-1)任意求和均可轉換爲求sum(1,n)

n=7:

sum(1,7)=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7] ;   

C[4]=A[1]+A[2]+A[3]+A[4];   C[6]=A[5]+A[6];   C[7]=A[7];

可以推出:   sum[7]=C[7]+C[6]+C[4];

序號寫爲二進制: sum(1,(111))=C[(111)]+C[(110)]+C[(100)];

int sum(int x)
{
	int sum = 0;
	while (x > 0)
	{
		sum += c[x];
		x -= Lowbit(x);
	}
	return sum;
}

x-=Lowbit(x)實際上就是將x二進制最後一個1減去,得到上一個父節點。而n的二進制裏最多有log(n)個1,所以查詢效率是log(n)的。

  • 單點更新:

要對最底層的值a[x]進行更新時,所有與它相關的父節點存儲的和也需要進行更新。最壞情況下爲修改第一個元素,最多有log(n)個祖先。

void update(int pos, int num)
{
	while (pos <= N)	//元素個數N
	{
		c[pos] += num;
		pos += Lowbit(x);
	}
}

侷限性:

不能進行區間更新;只能求和,不能求最值。

能用樹狀數組的都可以用線段樹。








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章