樹狀陣列的探索性理解

2022-08-03 06:03:10 字數 3075 閱讀 6136

給定乙個陣列a[n],求陣列

a[n]

的和sum

。一般的方法是遍歷陣列然後求和,這樣的時間複雜度為

o(n)

。而當修改了陣列中的元素,再次求陣列的和時,又要付出

o(n)

的時間代價。此時,我們可以用樹狀陣列來求和陣列的和。得到樹狀陣列

c[n]

後,時間複雜度將由

o(n)

變為o(lgn)

。這是如何實現的呢?下面我們將按照

:lowbit()函式

-->

樹狀陣列

-->

樹狀陣列索引的意義

-->

樹狀陣列的求和函式

-->

被運算元組更新資料,順序介紹這一巧妙的神器。

(1)lowbit()函式

lowbit()函式是對整數的位操作,返回乙個二進位制數的最低位「

1」。如

10(10)=01010(2)

,返回最低位的「

1」,即2。

lowbit()

函式不是庫函式,需要自己定義。

int lowbit(int x)

return x&-x;

原理(以

10為例):

運用計算機的補碼運算規則:原碼取反+1。

原碼取反後,各位與原二進位制數相反,lowbit位(含

)以後全變為1:

原碼:01010

反碼:00101

反碼加一後,二進位制的屬性導致各位都受影響(從最低位向高位進一,直到遇到乙個

0位變為1):

補碼:00110

此時,lowbit位前各位與原碼相反,

lowbit

位相等,

lowbit

位後全為0。

將補碼與原碼進行&(與

)運算,便可得到只有

lowbit位為1

的二進位制數。

原碼:01100

補碼:00110

結果:00100(與運算後)

int lowbit(int x)

return x&(x&(x^(x-1));

亦可實現返回最低位「

1」,讀者可自行推導。

(2)樹狀陣列

如圖所示為樹狀陣列的表示形式,下面給出樹狀陣列的定義: cn=a(n-a^k+1)+......+a(n)(k為

n的二進位制表示中從右向左數的

0的個數,

a^k可用

lowbit

函式求出

)。到此,讀者也許在思考此圖劃分的原因吧。這正是本人思考了很久的點,下面通過陣列索引(下標)的意義來理解這種結構。

(3)樹狀陣列索引的意義

在圖中我們可以看到樹狀陣列c的索引與要求和的陣列

a的索引是一一對應的。暫且理解陣列

c的下標意義為對陣列

a求和的元素數量。

c[1]=a1(a陣列第

1個數,下同

)            1:0001

c[2]=a1+a2                                       2:0010

c[3]=a1+a2+a3                                 3:0011

c[4]=a1+a2+a3+a4                           4:0100

c[5]=a1+a2+a3+a4+a5                      5:0101

c[6]=a1+a2+a3+a4+a5+a6                6:0110

c[7]=a1+a2+a3+a4+a5+a6+a7          7:0111

c[8]=a1+a2+a3+a4+a5+a6+a7+a8    8:1000

可見每一位索引對應的處理元素個數都可通過索引二進位制表示後不斷進行lowbit操作求得:

7=0001+0010+0100=1+2+4

。而lowbit

位以前的非零位則是已經處理過的。為了實現與

lowbit

前非零位的銜接

((2)

中的cn公式)

,索引對應的元素在被運算元組

a中的操數量即為索引的

lowbit

。即當前處理位置減去已經處理過的元素數量。之前的計算結果可通過不斷進行

n-=lowbit(n)

得到(n

為當前索引值)。

在此以c[7]和

c[8]為例(

此例中索引為在陣列的位序,即下標從1開始

):c[7]=a[7-lowbit[7]+1]+....+a[7].此處兩索引相等,為

a[7].

7-lowbit(7)=6

c[6]=a[6-lowbit(6)+1]+....+a[6]=a[5]+a[6]

6-lowbit(6)=4

c[4]=a[4-lowbit(4)+1]+.....+a[4]=a[1]+a[2]+a[3]+a[4]

4-lowbit(4)=0,結束。

c[8]=a[8-lowbit(8)+1]+...+a[8]=a[1]+a[2]+...a[8]

8-lowbit(8)=0,結束。

由此可以結合樹狀陣列下標的意義理解上圖的結構。

(4)求陣列的和:

int sum(int n)

int sum=0;

while(n>0)

sum+=c[n];

n-=lowbit(n);/*此處便可看出時間複雜度

o(lgn)

的由來。因為每次

lowbit

運算都是對原運算元除以二。

*/return  sum;

(5)被運算元組更新資料(對a中第

i個數加

x)此時可以更好的體現樹狀陣列的優勢:o(lgn)

void change(int i,int x)

while(i<=n)

c[i]=c[i]+x;

i+=lowbit(i);

資料的探索性分析

1.簡單統計量分析 極差,最大值,最小值 2.3 原則 如果資料服從正態分佈,在3 原則下,異常值被定義為一組測定值中與平均值的偏差超過3倍標準差的值。如果資料不服從正態分佈,也可以用標準差作為 來進行倍數描述 3.箱型圖分析 在箱型圖中,異常值被定義為小於ql 1.5iqr或大於qu 1.5iqr...

《權力的遊戲》Python探索性分析

權力的遊戲 game of thrones 是美國hbo電視網製作推出的一部中世紀史詩奇幻題材的電視劇集。該劇改編自美國作家喬治 r r 馬丁的奇幻 冰與火之歌 系列。該劇成功塑造成千上萬形象飽滿的人物角色 怪誕獨特充滿想象的風土人情,其空間之完整 細節之豐富 敘事之恣意讓人感嘆!現在讓我們用資料分...

談談測試中的探索性思維

不知大家是否有看過 探索性測試 這本書,裡面講的是探索測試中的一些思維。先問乙個問題,有沒有人會這樣想 測試比開發要難。有人會說,開發要求掌握的技能比測試的技能更精,怎麼會測試比開發難呢?先聽聽我怎麼想的,開發和測試由於角色的不同,必然會導致一些思維的不同。如一般的開發人員更多站在編碼的角度 這時候...