版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
樹狀數(shù)組的構(gòu)建與應(yīng)用方法一、樹狀數(shù)組概述
樹狀數(shù)組(BinaryIndexedTree,BIT),又稱Fenwick樹,是一種高效的數(shù)據(jù)結(jié)構(gòu),主要用于處理可變數(shù)組中的前綴和問題。它結(jié)合了二叉索引樹和數(shù)組的特點,通過巧妙的索引壓縮技術(shù),實現(xiàn)了對數(shù)組元素的快速更新和前綴和查詢。
(一)樹狀數(shù)組的基本概念
1.定義:樹狀數(shù)組是一種基于數(shù)組實現(xiàn)的數(shù)據(jù)結(jié)構(gòu),通過特殊的方式維護前綴和,支持對數(shù)時間復(fù)雜度的更新和查詢操作。
2.特點:
-索引從1開始,便于計算父節(jié)點和子節(jié)點關(guān)系。
-支持區(qū)間查詢和單點更新,效率高。
-適用于頻繁更新的場景,如動態(tài)數(shù)組求和。
(二)樹狀數(shù)組的應(yīng)用場景
1.前綴和查詢:快速計算數(shù)組中前n個元素的和。
2.區(qū)間和查詢:高效計算數(shù)組中任意區(qū)間的和。
3.單點更新:快速更新數(shù)組中的某個元素,并同步影響相關(guān)前綴和。
4.差分數(shù)組:結(jié)合差分思想,解決區(qū)間增量問題。
二、樹狀數(shù)組的構(gòu)建方法
樹狀數(shù)組的構(gòu)建基于二叉樹的性質(zhì),通過將數(shù)組索引映射到樹狀結(jié)構(gòu)實現(xiàn)。具體構(gòu)建步驟如下:
(一)初始化數(shù)組
1.創(chuàng)建一個大小為n+1的數(shù)組(從1開始),初始化所有元素為0。
2.示例:若n=5,則數(shù)組為[0,0,0,0,0,0]。
(二)更新操作實現(xiàn)
1.定義更新函數(shù):通過遞歸或迭代方式,將當前元素及其祖先節(jié)點更新為新的值。
2.計算父節(jié)點:當前索引j的父節(jié)點索引為floor((j+1)/2)。
3.示例:更新索引3的值為5,則依次更新索引3、2、1。
(三)前綴和查詢實現(xiàn)
1.定義查詢函數(shù):通過累加當前節(jié)點及其祖先節(jié)點的值,計算前綴和。
2.計算父節(jié)點:與更新操作相同,使用floor((j+1)/2)計算父節(jié)點。
3.示例:查詢索引4的前綴和,累加索引4、2、1的值。
三、樹狀數(shù)組的應(yīng)用實例
(一)前綴和查詢
1.初始化數(shù)組:[0,1,3,4,7,8]。
2.查詢前綴和sum(3)=1+3+4=8。
3.實現(xiàn)步驟:
-sum(3)=tree[3]+tree[2]+tree[1]。
(二)區(qū)間和查詢
1.通過前綴和計算區(qū)間和:sum(l,r)=sum(r)-sum(l-1)。
2.示例:sum(2,4)=sum(4)-sum(1)=7-1=6。
(三)單點更新
1.更新索引2的值為6,則依次更新tree[2]、tree[1]、tree[0]。
2.更新后數(shù)組:[0,6,9,4,7,8]。
(四)差分數(shù)組應(yīng)用
1.差分數(shù)組定義:diff[i]=arr[i]-arr[i-1]。
2.通過差分數(shù)組實現(xiàn)區(qū)間增量:
-給區(qū)間[l,r]增加v,則diff[l]+=v,diff[r+1]-=v。
3.還原原數(shù)組:通過前綴和計算arr[i]=arr[0]+diff[1]+...+diff[i]。
四、樹狀數(shù)組的優(yōu)缺點
(一)優(yōu)點
1.時間效率高:更新和查詢均為O(logn)復(fù)雜度。
2.空間效率低:僅需O(n)的存儲空間。
3.實現(xiàn)簡單:相比線段樹更易理解和編寫。
(二)缺點
1.功能受限:僅支持前綴和相關(guān)操作,無法處理更復(fù)雜的區(qū)間查詢。
2.適用場景有限:不適用于需要動態(tài)區(qū)間刪除或插入的場景。
五、總結(jié)
樹狀數(shù)組是一種高效的前綴和處理工具,通過索引壓縮技術(shù)實現(xiàn)快速更新和查詢。它適用于動態(tài)數(shù)組求和、區(qū)間和計算等場景,但功能相對單一。在實際應(yīng)用中,可根據(jù)需求選擇是否使用樹狀數(shù)組。
六、樹狀數(shù)組的構(gòu)建與初始化細節(jié)
(一)數(shù)組的初始化
1.存儲結(jié)構(gòu)設(shè)計:首先,需要創(chuàng)建一個一維數(shù)組`tree`,其大小為`n+1`(其中`n`是原數(shù)組的最大索引值)。數(shù)組`tree`的索引從1開始使用,索引0通常不使用或用于特殊標記。初始化時,將`tree`中的所有元素設(shè)置為0。這種從1開始索引的設(shè)計是為了方便后續(xù)計算父節(jié)點和子節(jié)點的索引。
示例:假設(shè)原數(shù)組的大小為5,其元素索引為1,2,3,4,5。則創(chuàng)建的`tree`數(shù)組大小為6,初始化后為`[0,0,0,0,0,0]`。
2.明確數(shù)組用途:在初始化前,明確該樹狀數(shù)組將要處理的具體問題,例如是用于單點更新和前綴和查詢,還是結(jié)合差分數(shù)組處理區(qū)間增量問題。不同的應(yīng)用可能需要微調(diào)初始化或更新邏輯。
(二)樹狀數(shù)組的核心構(gòu)建邏輯——低有效位(LowestOneBit,LBS)
樹狀數(shù)組的更新和查詢操作都依賴于對索引進行低有效位(LBS)的計算。LBS表示一個數(shù)的二進制表示中最低位的1所在的位置。計算一個數(shù)`j`的LBS有多種方法,常用的有兩種:
1.位運算方法:`j&(-j)`。這個運算利用了補碼的性質(zhì),`-j`是`j`的二進制按位取反加1。例如,`j=6`(二進制`110`),`-j=-6`(二進制`...11111010`),`j&(-j)=2`(二進制`10`)。
2.移位減法方法:`j&~(j-1)`。這個運算通過將`j`減1后按位取反與`j`進行按位與,結(jié)果就是最低位的1。例如,`j=6`(`110`),`j-1=5`(`101`),`~(j-1)=...01001011`,`j&~(j-1)=2`(`010`)。
作用:LBS在樹狀數(shù)組中代表了從當前索引`j`向上跳轉(zhuǎn)到達的父節(jié)點索引。每次更新或查詢時,都需要通過`j-=j&(-j)`或`j-=j&~(j-1)`來找到下一個需要處理的祖先節(jié)點,直到`j`減少到0。
七、樹狀數(shù)組的更新操作詳解
更新操作的目標是將數(shù)組中某個位置的值增加一個給定的值`v`(可以是正數(shù)或負數(shù)),并相應(yīng)地更新樹狀數(shù)組`tree`中的所有受影響的節(jié)點,以保持前綴和的正確性。更新過程遵循“自底向上”的原則。
(一)更新函數(shù)的基本結(jié)構(gòu)
1.輸入?yún)?shù):接收當前要更新的索引`index`和更新的增量值`delta`(即`new_value-old_value`)。
2.循環(huán)或遞歸過程:通過不斷減去LBS來向上遍歷樹狀結(jié)構(gòu),直到遍歷完所有受影響的節(jié)點。
(二)更新操作的步驟(以迭代方式為例)
1.檢查邊界:首先檢查`index`是否有效(通常要求`index>=1`)。如果`index`無效,直接返回。
2.進入循環(huán):當`index>0`時,執(zhí)行更新操作。
3.計算當前節(jié)點:將增量`delta`加到`tree[index]`上:`tree[index]+=delta`。
4.計算下一個節(jié)點索引:使用LBS方法計算當前索引`index`的父節(jié)點索引:`index-=index&(-index)`。這會跳轉(zhuǎn)到下一個需要更新的祖先節(jié)點。
5.循環(huán)條件:重復(fù)步驟3和4,直到`index`減少到0。
6.結(jié)束更新:當`index`為0時,表示所有受影響的節(jié)點已經(jīng)更新完畢,退出循環(huán)。
(三)更新操作的示例
假設(shè)`tree=[0,0,0,0,0,0]`,要更新索引3的值,將其增加5(即`old_value=0`,`new_value=5`,`delta=5`)。
1.`index=3`,`tree[3]=0+5=5`。
2.`index=3&(-3)=3&1=1`。
3.`tree[1]=0+5=5`。
4.`index=1&(-1)=1&1=1`。
5.`tree[1]=5+5=10`。
6.`index=1&(-1)=1&1=1`。
7.`index`不再大于0,更新結(jié)束。最終`tree=[0,10,0,5,0,0]`。
八、樹狀數(shù)組的查詢操作詳解
查詢操作的目標是計算數(shù)組中從索引1到指定索引`index`的所有元素的和,即前綴和`sum(1,index)`。查詢過程遵循“自頂向下”的原則,從根節(jié)點開始,根據(jù)當前節(jié)點與目標索引的LBS關(guān)系決定是向左還是向右子樹遞歸查詢。
(一)查詢函數(shù)的基本結(jié)構(gòu)
1.輸入?yún)?shù):接收查詢的目標索引`index`。
2.累積和變量:定義一個變量(如`result`)用于累積沿途節(jié)點值,初始值為0。
(二)查詢操作的步驟(以遞歸方式為例)
1.檢查邊界:首先檢查`index`是否有效(通常要求`index>=1`)。如果`index`無效,直接返回0。
2.進入遞歸:當`index>0`時,執(zhí)行查詢操作。
3.累加當前節(jié)點:將`tree[index]`的值加到累積和變量`result`上:`result+=tree[index]`。
4.計算下一個查詢節(jié)點索引:使用LBS方法計算當前索引`index`的下一個祖先節(jié)點索引:`index-=index&(-index)`。
5.遞歸調(diào)用:如果新的`index`大于0,遞歸調(diào)用查詢函數(shù)`query(index)`,將返回值加到`result`上。
6.返回結(jié)果:當`index`減少到0時,表示所有相關(guān)節(jié)點已經(jīng)查詢完畢,返回累積和`result`。
(三)查詢操作的步驟(以迭代方式為例)
1.初始化:定義累積和變量`result=0`。
2.進入循環(huán):當`index>0`時,執(zhí)行查詢操作。
3.累加當前節(jié)點:將`tree[index]`的值加到`result`上:`result+=tree[index]`。
4.計算下一個查詢節(jié)點索引:使用LBS方法計算當前索引`index`的下一個祖先節(jié)點索引:`index-=index&(-index)`。
5.循環(huán)條件:重復(fù)步驟3和4,直到`index`減少到0。
6.返回結(jié)果:當`index`為0時,返回累積和`result`。
(四)查詢操作的示例
假設(shè)`tree=[0,10,0,5,0,0]`,要查詢索引4的前綴和`sum(1,4)`。
1.`index=4`,`result=0+tree[4]=0+0=0`。
2.`index=4&(-4)=4&4=4`。
3.`result=0+tree[4]=0+0=0`。
4.`index=4&(-4)=4&4=4`。
5.`index`不再大于0,查詢結(jié)束。最終`sum(1,4)=0`。
九、樹狀數(shù)組與差分數(shù)組的結(jié)合應(yīng)用
樹狀數(shù)組可以與差分數(shù)組結(jié)合,高效地處理區(qū)間增量問題。這種組合特別適用于需要頻繁對數(shù)組中的某個連續(xù)區(qū)間進行統(tǒng)一加/減操作,然后查詢整個數(shù)組或其子數(shù)組狀態(tài)的場景。
(一)差分數(shù)組的基本概念
1.定義:創(chuàng)建一個與原數(shù)組等長的差分數(shù)組`diff`。`diff[i]`存儲原數(shù)組`arr`中`arr[i]`與`arr[i-1]`的差值(`diff[i]=arr[i]-arr[i-1]`)。注意`diff[0]`通常沒有定義或為0。
2.還原原數(shù)組:通過差分數(shù)組可以高效地還原原數(shù)組。`arr[i]=arr[0]+sum(diff[1]...diff[i])`。這正是樹狀數(shù)組擅長的操作。
(二)利用樹狀數(shù)組實現(xiàn)區(qū)間增量
1.目標:對原數(shù)組`arr`的區(qū)間`[l,r]`進行增量操作,即`arr[l]+=v`,`arr[l+1]+=v`,...,`arr[r]+=v`。
2.轉(zhuǎn)換為差分數(shù)組操作:根據(jù)差分數(shù)組的定義,這等價于`diff[l]+=v`和`diff[r+1]-=v`。
3.使用樹狀數(shù)組更新:
對`diff[l]`執(zhí)行樹狀數(shù)組的更新操作,將`diff[l]`增加`v`。
對`diff[r+1]`執(zhí)行樹狀數(shù)組的更新操作,將`diff[r+1]`減少`v`(即增量為`-v`)。
4.操作時間復(fù)雜度:每次區(qū)間增量操作都可以在O(logn)時間內(nèi)完成。
(三)利用樹狀數(shù)組查詢原數(shù)組狀態(tài)
1.目標:在進行了多次區(qū)間增量操作后,查詢原數(shù)組`arr`中任意區(qū)間`[q_l,q_r]`的和,或查詢整個數(shù)組的狀態(tài)。
2.轉(zhuǎn)換為差分數(shù)組查詢:查詢`sum(arr[q_l]...arr[q_r])`等價于`sum(diff[1]...diff[q_r])-sum(diff[1]...diff[q_l-1])`。
3.使用樹狀數(shù)組查詢:
使用樹狀數(shù)組的查詢操作計算`sum(diff[1]...diff[q_r])`。
使用樹狀數(shù)組的查詢操作計算`sum(diff[1]...diff[q_l-1])`。
最終結(jié)果為兩者之差。
4.操作時間復(fù)雜度:每次區(qū)間查詢或單點查詢都可以在O(logn)時間內(nèi)完成。
(四)應(yīng)用場景示例
1.模擬用戶在線時長變化:維護一個用戶在線時長數(shù)組。當用戶上線時,對起始時間對應(yīng)的區(qū)間增加時長;用戶下線時,對結(jié)束時間對應(yīng)的區(qū)間增加時長(負值)。隨時可以查詢某個時間段的累計在線用戶總時長。
2.道路維修影響范圍統(tǒng)計:維護一個道路通行狀態(tài)數(shù)組。當某段道路開始維修時,對起點和終點進行區(qū)間增量操作(例如,將通行能力降為0)。隨時可以查詢某個區(qū)域的平均通行影響程度。
十、樹狀數(shù)組的優(yōu)缺點總結(jié)與選擇考量
(一)優(yōu)點
1.高效性:對于單點更新和區(qū)間(前綴)和查詢,時間復(fù)雜度均為O(logn),遠快于未優(yōu)化的O(n)方法。
2.空間效率:僅需一個大小為O(n)的數(shù)組作為存儲結(jié)構(gòu),空間占用小。
3.實現(xiàn)相對簡單:相比線段樹、段樹等更復(fù)雜的數(shù)據(jù)結(jié)構(gòu),樹狀數(shù)組的概念和實現(xiàn)代碼通常更簡潔易懂。
4.特定場景適用:特別適合只需要進行單點更新和查詢前綴和/區(qū)間和的靜態(tài)或半動態(tài)數(shù)組問題。
(二)缺點
1.功能限制:樹狀數(shù)組的核心功能僅限于前綴和及其相關(guān)操作。無法直接支持區(qū)間更新、區(qū)間查詢、動態(tài)維護最值等更復(fù)雜的查詢或更新需求。
2.更新與查詢的耦合:更新操作會影響多個節(jié)點,查詢操作依賴于更新后的全局狀態(tài)。對于某些需要獨立處理不同區(qū)域更新的場景,不夠靈活。
3.不支持某些操作:例如,無法直接高效地回答“在數(shù)組中查找第k大的元素”這類問題。
(三)選擇考量
1.問題需求匹配:如果問題核心需求是頻繁的單點更新和前綴和/區(qū)間和查詢,樹狀數(shù)組是非常好的選擇。否則,應(yīng)考慮其他數(shù)據(jù)結(jié)構(gòu)。
2.操作類型組合:如果問題需要混合多種操作(如更新、查詢、最值查詢等),可能需要線段樹或樹狀數(shù)組與其他數(shù)據(jù)結(jié)構(gòu)的組合,或者選擇功能更全面的線段樹。
3.數(shù)據(jù)規(guī)模與動態(tài)性:對于大規(guī)模數(shù)據(jù)且更新操作遠多于查詢操作,樹狀數(shù)組的O(logn)性能優(yōu)勢明顯。
4.實現(xiàn)復(fù)雜度容忍度:如果對代碼實現(xiàn)的簡潔性要求較高,樹狀數(shù)組優(yōu)于復(fù)雜度更高的數(shù)據(jù)結(jié)構(gòu)。
十一、樹狀數(shù)組的常見變種
雖然基本的樹狀數(shù)組(BinaryIndexedTree)是最常用的形式,但根據(jù)不同的應(yīng)用需求,也衍生出一些變種,它們在特定場景下可能更具優(yōu)勢。
(一)二維樹狀數(shù)組(2DBinaryIndexedTree/FenwickTree2D)
1.應(yīng)用場景:用于處理二維數(shù)組的前綴和查詢和更新問題,例如在網(wǎng)格地圖上進行頻繁的增量更新和區(qū)域求和計算。
2.構(gòu)建方式:通常有兩種構(gòu)建方式:
方法一(二維獨立):構(gòu)建兩個一維樹狀數(shù)組`tree1`和`tree2`,分別對行和列進行維護。查詢時需要分別查詢行和列的范圍,更新時也需要分別在兩個數(shù)組中進行。
方法二(二維聯(lián)合):將二維坐標`(x,y)`映射到一維索引`index=xwidth+y+1`(其中`width`是列數(shù))。然后在這個一維數(shù)組上構(gòu)建樹狀數(shù)組。查詢和更新操作需要轉(zhuǎn)換為一維索引進行。
3.操作復(fù)雜度:無論是哪種方式,單次查詢和更新操作的時間復(fù)雜度通常都是O(lognlogm),其中`n`是行數(shù),`m`是列數(shù)。
(二)帶權(quán)樹狀數(shù)組(WeightedFenwickTree)
1.應(yīng)用場景:用于處理與權(quán)重相關(guān)的查詢和更新問題,例如在圖論中處理與邊權(quán)重相關(guān)的動態(tài)路徑和問題。
2.特點:除了支持普通的加法更新和前綴和查詢外,還支持與權(quán)重相關(guān)的更復(fù)雜操作,如查詢某個權(quán)重的第k小元素等。
3.實現(xiàn)復(fù)雜度:實現(xiàn)相對復(fù)雜,通常需要結(jié)合二叉搜索樹或排序數(shù)組來維護權(quán)重順序信息。
(三)可變樹狀數(shù)組(MutableFenwickTree/BinaryIndexedTreewithPointUpdateandRangeQuery)
1.應(yīng)用場景:標準的樹狀數(shù)組在處理區(qū)間查詢時效率高,但在處理區(qū)間更新(如`add(l,r,v)`)時需要分解為兩個點更新`add(l,v)`和`add(r+1,-v)`,然后進行區(qū)間查詢。如果需要直接支持高效的區(qū)間更新,則需要可變樹狀數(shù)組。
2.特點:通過更復(fù)雜的內(nèi)部結(jié)構(gòu)(如結(jié)合了線段樹的思想),使得區(qū)間更新和區(qū)間查詢都能達到O(logn)的時間復(fù)雜度。
3.實現(xiàn)復(fù)雜度:實現(xiàn)比標準樹狀數(shù)組復(fù)雜得多。
十二、總結(jié)
樹狀數(shù)組是一種強大且實用的數(shù)據(jù)結(jié)構(gòu),通過巧妙的索引映射和低有效位運算,實現(xiàn)了對動態(tài)數(shù)組中前綴和的高效管理。它支持O(logn)時間復(fù)雜度的單點更新和區(qū)間(前綴)和查詢,在許多實際問題中能夠顯著提升性能。理解樹狀數(shù)組的構(gòu)建邏輯、更新和查詢步驟,以及如何將其與差分數(shù)組結(jié)合應(yīng)用,對于解決涉及動態(tài)數(shù)據(jù)求和的問題至關(guān)重要。在選擇數(shù)據(jù)結(jié)構(gòu)時,應(yīng)充分考慮問題的具體需求,判斷樹狀數(shù)組是否是最佳匹配,或者在必要時考慮其變種或其他更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。
一、樹狀數(shù)組概述
樹狀數(shù)組(BinaryIndexedTree,BIT),又稱Fenwick樹,是一種高效的數(shù)據(jù)結(jié)構(gòu),主要用于處理可變數(shù)組中的前綴和問題。它結(jié)合了二叉索引樹和數(shù)組的特點,通過巧妙的索引壓縮技術(shù),實現(xiàn)了對數(shù)組元素的快速更新和前綴和查詢。
(一)樹狀數(shù)組的基本概念
1.定義:樹狀數(shù)組是一種基于數(shù)組實現(xiàn)的數(shù)據(jù)結(jié)構(gòu),通過特殊的方式維護前綴和,支持對數(shù)時間復(fù)雜度的更新和查詢操作。
2.特點:
-索引從1開始,便于計算父節(jié)點和子節(jié)點關(guān)系。
-支持區(qū)間查詢和單點更新,效率高。
-適用于頻繁更新的場景,如動態(tài)數(shù)組求和。
(二)樹狀數(shù)組的應(yīng)用場景
1.前綴和查詢:快速計算數(shù)組中前n個元素的和。
2.區(qū)間和查詢:高效計算數(shù)組中任意區(qū)間的和。
3.單點更新:快速更新數(shù)組中的某個元素,并同步影響相關(guān)前綴和。
4.差分數(shù)組:結(jié)合差分思想,解決區(qū)間增量問題。
二、樹狀數(shù)組的構(gòu)建方法
樹狀數(shù)組的構(gòu)建基于二叉樹的性質(zhì),通過將數(shù)組索引映射到樹狀結(jié)構(gòu)實現(xiàn)。具體構(gòu)建步驟如下:
(一)初始化數(shù)組
1.創(chuàng)建一個大小為n+1的數(shù)組(從1開始),初始化所有元素為0。
2.示例:若n=5,則數(shù)組為[0,0,0,0,0,0]。
(二)更新操作實現(xiàn)
1.定義更新函數(shù):通過遞歸或迭代方式,將當前元素及其祖先節(jié)點更新為新的值。
2.計算父節(jié)點:當前索引j的父節(jié)點索引為floor((j+1)/2)。
3.示例:更新索引3的值為5,則依次更新索引3、2、1。
(三)前綴和查詢實現(xiàn)
1.定義查詢函數(shù):通過累加當前節(jié)點及其祖先節(jié)點的值,計算前綴和。
2.計算父節(jié)點:與更新操作相同,使用floor((j+1)/2)計算父節(jié)點。
3.示例:查詢索引4的前綴和,累加索引4、2、1的值。
三、樹狀數(shù)組的應(yīng)用實例
(一)前綴和查詢
1.初始化數(shù)組:[0,1,3,4,7,8]。
2.查詢前綴和sum(3)=1+3+4=8。
3.實現(xiàn)步驟:
-sum(3)=tree[3]+tree[2]+tree[1]。
(二)區(qū)間和查詢
1.通過前綴和計算區(qū)間和:sum(l,r)=sum(r)-sum(l-1)。
2.示例:sum(2,4)=sum(4)-sum(1)=7-1=6。
(三)單點更新
1.更新索引2的值為6,則依次更新tree[2]、tree[1]、tree[0]。
2.更新后數(shù)組:[0,6,9,4,7,8]。
(四)差分數(shù)組應(yīng)用
1.差分數(shù)組定義:diff[i]=arr[i]-arr[i-1]。
2.通過差分數(shù)組實現(xiàn)區(qū)間增量:
-給區(qū)間[l,r]增加v,則diff[l]+=v,diff[r+1]-=v。
3.還原原數(shù)組:通過前綴和計算arr[i]=arr[0]+diff[1]+...+diff[i]。
四、樹狀數(shù)組的優(yōu)缺點
(一)優(yōu)點
1.時間效率高:更新和查詢均為O(logn)復(fù)雜度。
2.空間效率低:僅需O(n)的存儲空間。
3.實現(xiàn)簡單:相比線段樹更易理解和編寫。
(二)缺點
1.功能受限:僅支持前綴和相關(guān)操作,無法處理更復(fù)雜的區(qū)間查詢。
2.適用場景有限:不適用于需要動態(tài)區(qū)間刪除或插入的場景。
五、總結(jié)
樹狀數(shù)組是一種高效的前綴和處理工具,通過索引壓縮技術(shù)實現(xiàn)快速更新和查詢。它適用于動態(tài)數(shù)組求和、區(qū)間和計算等場景,但功能相對單一。在實際應(yīng)用中,可根據(jù)需求選擇是否使用樹狀數(shù)組。
六、樹狀數(shù)組的構(gòu)建與初始化細節(jié)
(一)數(shù)組的初始化
1.存儲結(jié)構(gòu)設(shè)計:首先,需要創(chuàng)建一個一維數(shù)組`tree`,其大小為`n+1`(其中`n`是原數(shù)組的最大索引值)。數(shù)組`tree`的索引從1開始使用,索引0通常不使用或用于特殊標記。初始化時,將`tree`中的所有元素設(shè)置為0。這種從1開始索引的設(shè)計是為了方便后續(xù)計算父節(jié)點和子節(jié)點的索引。
示例:假設(shè)原數(shù)組的大小為5,其元素索引為1,2,3,4,5。則創(chuàng)建的`tree`數(shù)組大小為6,初始化后為`[0,0,0,0,0,0]`。
2.明確數(shù)組用途:在初始化前,明確該樹狀數(shù)組將要處理的具體問題,例如是用于單點更新和前綴和查詢,還是結(jié)合差分數(shù)組處理區(qū)間增量問題。不同的應(yīng)用可能需要微調(diào)初始化或更新邏輯。
(二)樹狀數(shù)組的核心構(gòu)建邏輯——低有效位(LowestOneBit,LBS)
樹狀數(shù)組的更新和查詢操作都依賴于對索引進行低有效位(LBS)的計算。LBS表示一個數(shù)的二進制表示中最低位的1所在的位置。計算一個數(shù)`j`的LBS有多種方法,常用的有兩種:
1.位運算方法:`j&(-j)`。這個運算利用了補碼的性質(zhì),`-j`是`j`的二進制按位取反加1。例如,`j=6`(二進制`110`),`-j=-6`(二進制`...11111010`),`j&(-j)=2`(二進制`10`)。
2.移位減法方法:`j&~(j-1)`。這個運算通過將`j`減1后按位取反與`j`進行按位與,結(jié)果就是最低位的1。例如,`j=6`(`110`),`j-1=5`(`101`),`~(j-1)=...01001011`,`j&~(j-1)=2`(`010`)。
作用:LBS在樹狀數(shù)組中代表了從當前索引`j`向上跳轉(zhuǎn)到達的父節(jié)點索引。每次更新或查詢時,都需要通過`j-=j&(-j)`或`j-=j&~(j-1)`來找到下一個需要處理的祖先節(jié)點,直到`j`減少到0。
七、樹狀數(shù)組的更新操作詳解
更新操作的目標是將數(shù)組中某個位置的值增加一個給定的值`v`(可以是正數(shù)或負數(shù)),并相應(yīng)地更新樹狀數(shù)組`tree`中的所有受影響的節(jié)點,以保持前綴和的正確性。更新過程遵循“自底向上”的原則。
(一)更新函數(shù)的基本結(jié)構(gòu)
1.輸入?yún)?shù):接收當前要更新的索引`index`和更新的增量值`delta`(即`new_value-old_value`)。
2.循環(huán)或遞歸過程:通過不斷減去LBS來向上遍歷樹狀結(jié)構(gòu),直到遍歷完所有受影響的節(jié)點。
(二)更新操作的步驟(以迭代方式為例)
1.檢查邊界:首先檢查`index`是否有效(通常要求`index>=1`)。如果`index`無效,直接返回。
2.進入循環(huán):當`index>0`時,執(zhí)行更新操作。
3.計算當前節(jié)點:將增量`delta`加到`tree[index]`上:`tree[index]+=delta`。
4.計算下一個節(jié)點索引:使用LBS方法計算當前索引`index`的父節(jié)點索引:`index-=index&(-index)`。這會跳轉(zhuǎn)到下一個需要更新的祖先節(jié)點。
5.循環(huán)條件:重復(fù)步驟3和4,直到`index`減少到0。
6.結(jié)束更新:當`index`為0時,表示所有受影響的節(jié)點已經(jīng)更新完畢,退出循環(huán)。
(三)更新操作的示例
假設(shè)`tree=[0,0,0,0,0,0]`,要更新索引3的值,將其增加5(即`old_value=0`,`new_value=5`,`delta=5`)。
1.`index=3`,`tree[3]=0+5=5`。
2.`index=3&(-3)=3&1=1`。
3.`tree[1]=0+5=5`。
4.`index=1&(-1)=1&1=1`。
5.`tree[1]=5+5=10`。
6.`index=1&(-1)=1&1=1`。
7.`index`不再大于0,更新結(jié)束。最終`tree=[0,10,0,5,0,0]`。
八、樹狀數(shù)組的查詢操作詳解
查詢操作的目標是計算數(shù)組中從索引1到指定索引`index`的所有元素的和,即前綴和`sum(1,index)`。查詢過程遵循“自頂向下”的原則,從根節(jié)點開始,根據(jù)當前節(jié)點與目標索引的LBS關(guān)系決定是向左還是向右子樹遞歸查詢。
(一)查詢函數(shù)的基本結(jié)構(gòu)
1.輸入?yún)?shù):接收查詢的目標索引`index`。
2.累積和變量:定義一個變量(如`result`)用于累積沿途節(jié)點值,初始值為0。
(二)查詢操作的步驟(以遞歸方式為例)
1.檢查邊界:首先檢查`index`是否有效(通常要求`index>=1`)。如果`index`無效,直接返回0。
2.進入遞歸:當`index>0`時,執(zhí)行查詢操作。
3.累加當前節(jié)點:將`tree[index]`的值加到累積和變量`result`上:`result+=tree[index]`。
4.計算下一個查詢節(jié)點索引:使用LBS方法計算當前索引`index`的下一個祖先節(jié)點索引:`index-=index&(-index)`。
5.遞歸調(diào)用:如果新的`index`大于0,遞歸調(diào)用查詢函數(shù)`query(index)`,將返回值加到`result`上。
6.返回結(jié)果:當`index`減少到0時,表示所有相關(guān)節(jié)點已經(jīng)查詢完畢,返回累積和`result`。
(三)查詢操作的步驟(以迭代方式為例)
1.初始化:定義累積和變量`result=0`。
2.進入循環(huán):當`index>0`時,執(zhí)行查詢操作。
3.累加當前節(jié)點:將`tree[index]`的值加到`result`上:`result+=tree[index]`。
4.計算下一個查詢節(jié)點索引:使用LBS方法計算當前索引`index`的下一個祖先節(jié)點索引:`index-=index&(-index)`。
5.循環(huán)條件:重復(fù)步驟3和4,直到`index`減少到0。
6.返回結(jié)果:當`index`為0時,返回累積和`result`。
(四)查詢操作的示例
假設(shè)`tree=[0,10,0,5,0,0]`,要查詢索引4的前綴和`sum(1,4)`。
1.`index=4`,`result=0+tree[4]=0+0=0`。
2.`index=4&(-4)=4&4=4`。
3.`result=0+tree[4]=0+0=0`。
4.`index=4&(-4)=4&4=4`。
5.`index`不再大于0,查詢結(jié)束。最終`sum(1,4)=0`。
九、樹狀數(shù)組與差分數(shù)組的結(jié)合應(yīng)用
樹狀數(shù)組可以與差分數(shù)組結(jié)合,高效地處理區(qū)間增量問題。這種組合特別適用于需要頻繁對數(shù)組中的某個連續(xù)區(qū)間進行統(tǒng)一加/減操作,然后查詢整個數(shù)組或其子數(shù)組狀態(tài)的場景。
(一)差分數(shù)組的基本概念
1.定義:創(chuàng)建一個與原數(shù)組等長的差分數(shù)組`diff`。`diff[i]`存儲原數(shù)組`arr`中`arr[i]`與`arr[i-1]`的差值(`diff[i]=arr[i]-arr[i-1]`)。注意`diff[0]`通常沒有定義或為0。
2.還原原數(shù)組:通過差分數(shù)組可以高效地還原原數(shù)組。`arr[i]=arr[0]+sum(diff[1]...diff[i])`。這正是樹狀數(shù)組擅長的操作。
(二)利用樹狀數(shù)組實現(xiàn)區(qū)間增量
1.目標:對原數(shù)組`arr`的區(qū)間`[l,r]`進行增量操作,即`arr[l]+=v`,`arr[l+1]+=v`,...,`arr[r]+=v`。
2.轉(zhuǎn)換為差分數(shù)組操作:根據(jù)差分數(shù)組的定義,這等價于`diff[l]+=v`和`diff[r+1]-=v`。
3.使用樹狀數(shù)組更新:
對`diff[l]`執(zhí)行樹狀數(shù)組的更新操作,將`diff[l]`增加`v`。
對`diff[r+1]`執(zhí)行樹狀數(shù)組的更新操作,將`diff[r+1]`減少`v`(即增量為`-v`)。
4.操作時間復(fù)雜度:每次區(qū)間增量操作都可以在O(logn)時間內(nèi)完成。
(三)利用樹狀數(shù)組查詢原數(shù)組狀態(tài)
1.目標:在進行了多次區(qū)間增量操作后,查詢原數(shù)組`arr`中任意區(qū)間`[q_l,q_r]`的和,或查詢整個數(shù)組的狀態(tài)。
2.轉(zhuǎn)換為差分數(shù)組查詢:查詢`sum(arr[q_l]...arr[q_r])`等價于`sum(diff[1]...diff[q_r])-sum(diff[1]...diff[q_l-1])`。
3.使用樹狀數(shù)組查詢:
使用樹狀數(shù)組的查詢操作計算`sum(diff[1]...diff[q_r])`。
使用樹狀數(shù)組的查詢操作計算`sum(diff[1]...diff[q_l-1])`。
最終結(jié)果為兩者之差。
4.操作時間復(fù)雜度:每次區(qū)間查詢或單點查詢都可以在O(logn)時間內(nèi)完成。
(四)應(yīng)用場景示例
1.模擬用戶在線時長變化:維護一個用戶在線時長數(shù)組。當用戶上線時,對起始時間對應(yīng)的區(qū)間增加時長;用戶下線時,對結(jié)束時間對應(yīng)的區(qū)間增加時長(負值)。隨時可以查詢某個時間段的累計在線用戶總時長。
2.道路維修影響范圍統(tǒng)計:維護一個道路通行狀態(tài)數(shù)組。當某段道路開始維修時,對起點和終點進行區(qū)間增量操作(例如,將通行能力降為0)。隨時可以查詢某個區(qū)域的平均通行影響程度。
十、樹狀數(shù)組的優(yōu)缺點總結(jié)與選擇考量
(一)優(yōu)點
1.高效性:對于單點更新和區(qū)間(前綴)和查詢,時間復(fù)雜度均為O(logn),遠快于未優(yōu)化的O(n)方法。
2.空間效率:僅需一個大小為O(n)的數(shù)組作為存儲結(jié)構(gòu),空間占用小。
3.實現(xiàn)相對簡單:相比線段樹、段樹等更復(fù)雜的數(shù)據(jù)結(jié)構(gòu),樹狀數(shù)組的概念和實現(xiàn)代碼通常更簡潔易懂。
4.特定場景適用:特別適合只需要進行單點更新和查詢前綴和/區(qū)間和的靜態(tài)或半動態(tài)數(shù)組問題。
(二)缺點
1.功能限制:樹狀數(shù)組的核心功能僅限于前綴和及其相關(guān)操作。無法直接支持區(qū)間更新、區(qū)間查詢、動態(tài)維護最值等更復(fù)雜的查詢或更新需求。
2.更新與查詢的耦合:更新操作會影響多個節(jié)點,查詢操作依賴于更新后的
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年大學二年級(數(shù)字經(jīng)濟)產(chǎn)業(yè)應(yīng)用階段測試題及答案
- 2025年大學大三(自動化)嵌入式系統(tǒng)開發(fā)綜合測試試題及答案
- 教學助產(chǎn)技術(shù)執(zhí)法檢查
- 通信線路工程各崗位職責及管理制度
- 養(yǎng)老院老人生活設(shè)施維修人員激勵制度
- 養(yǎng)老院老人心理咨詢服務(wù)質(zhì)量管理制度
- 養(yǎng)老院收費標準及退費制度
- 養(yǎng)老院入住老人生活照料服務(wù)規(guī)范制度
- 公共交通服務(wù)設(shè)施維護制度
- 2026年保險從業(yè)資格核心知識題庫含答案
- 2026 中考【初中道法時政熱點】
- 2025年上半年山東高速集團有限公司校園招聘(255人)筆試參考題庫附答案
- 故意傷害案件課件
- 膽管狹窄護理
- 消防操作員其他實操技能
- 2025年高考數(shù)學試題分類匯編:數(shù)列解析版
- 工程部物業(yè)消防知識培訓(xùn)課件
- 江西省婺源縣聯(lián)考2026屆數(shù)學七年級第一學期期末學業(yè)水平測試試題含解析
- 非煤礦山安全員題庫及答案解析
- 數(shù)據(jù)中心設(shè)備采購管理實施計劃
- 2025時事政治必考題50題(含答案)
評論
0/150
提交評論