程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++實用數據結構:二叉索引樹,數據結構二叉

C++實用數據結構:二叉索引樹,數據結構二叉

編輯:C++入門知識

C++實用數據結構:二叉索引樹,數據結構二叉


看下面這個問題(動態連續和查詢):

有一個數組A(長度為n),要求進行兩種操作: add(i,x):讓Ai增大x; query(a,b):詢問Aa+Aa+1+...+Ab的和; 若進行模擬,則每次query操作的最壞的時間復雜度為O(n),在n較大時速度較慢。用前綴和也不能提高效率(每次add操作最壞為O(n))。有一種數據結構,可以在O(n)時間裡初始化,用O(logn)的速度執行add操作或查詢前綴和,從而執行query操作。 首先,我們來介紹“lowbit”。對於一個數x,lowbit(x)是x的二進制裡最右面的1所代表的數字,例如lowbit(20)=4,因為20的二進制為10100,最右面的1代表4。怎樣計算lowbit呢?很簡單,lowbit(x)=x&-x。這是因為負數是用補碼保存的,-x就相當於(~x)+1。例(用8位計算):  20=(00010100) -20=(11101100) 現在我們來介紹二叉索引樹。二叉索引樹在程序中也是用數組來保存的。 C++實用數據結構:二叉索引樹 - 任清宇 - a1458814497的博客(畫得難看請見諒) 圖中,深灰色方塊代表樹中的結點(結點0為虛擬結點),灰色線段代表樹中的邊。這些邊並不需要顯式保存;對於一個節點x,若它是父結點的左子結點,則父結點編號為x-lowbit(x),否則為x+lowbit(x)。圖中的每個結點左側都有一個白色長條(包括它自己),如結點4的長條為1~4,節點3的長條為3~3。不難發現,結點x的長條為(x-lowbit(x)+1)~x。 然後,我們用一個數組S儲存每個結點的白色長條內的所有數的和。例如,S4=A1+A2+A3+A4。這樣,就可以使用一個輔助的前綴和數組,在O(n)時間內從左到右初始化S數組。代碼如下:     1 int n; 2 int S[maxn],A[mxan],S1[maxn]; 3 int begin() 4 { 5 memset(S1,0,sizeof(S1)); 6 for(int i=1;i<=n;i++) 7 { 8 S1[i]=S1[i-1]+A[i]; 9 S[i]=S1[i]-S1[i-lowbit(i)]; 10 } 11 } View Code

 

最後讓我們來實現add操作和查詢操作。對於某個add操作的結點i,它的修改會影響到那些結點呢?很顯然,在它下面的結點(lowbit比它小)不會受到影響,在它左邊的結點也不會受到影響,所以只需要考慮在它右邊且lowbit比它大的第一個結點,這個結點的白色長條一定覆蓋x。很顯然,這個結點的編號為i+lowbit(i)。 接下來,x結點不需要考慮了,讓我們來考慮i+lowbit(i)結點。與上面一樣,只需要考慮在它右邊且lowbit比它大的第一個結點,所以只需要讓i+=lowbit(i)。代碼如下: 1 void add(int i,int x) 2 { 3 //若需要其他操作,可以加一句: 4 //A[i]+=x; 5 while(i<=n) 6 { 7 S[i]+=x;i+=lowbit(i); 8 } 9 } View Code

 

查詢前綴和的方法與之類似,只是i+=lowbit(i);改成了i-=lowbit(i);這裡不再介紹證明方法,與上面類似。代碼如下:

1 int query2(int i) 2 { 3 int sum=0; 4 while(i!=0) 5 { 6 sum+=S[i];i-=lowbit(i); 7 } 8 return sum; 9 } 10 int query(int l,int r) 11 { 12 return query2(r)-query2(l-1); 13 } View Code

 

 

最後,若有建議請提出。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved