日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

js 数组 实现 完全树_算法和数据结构 | 树状数组(Binary Indexed Tree)

發(fā)布時間:2025/4/5 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 js 数组 实现 完全树_算法和数据结构 | 树状数组(Binary Indexed Tree) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本文來源于力扣圈子,作者:胡小旭。點(diǎn)擊查看原文

力扣?leetcode-cn.com

樹狀數(shù)組或二叉索引樹(英語:Binary Indexed Tree),又以其發(fā)明者命名為 Fenwick 樹。其初衷是解決數(shù)據(jù)壓縮里的累積頻率(Cumulative Frequency)的計算問題,現(xiàn)多用于高效計算數(shù)列的前綴和, 區(qū)間和。它可以以

的時間得到任意前綴和,并同時支持在 時間內(nèi)支持動態(tài)單點(diǎn)值的修改。空間復(fù)雜度 。

文章先介紹低位運(yùn)算(lowbit)的基本知識,再提及如何將一個整數(shù)劃分為

個區(qū)間的運(yùn)算過程,進(jìn)而延展到如何將線性序列以樹行結(jié)構(gòu)進(jìn)行存取,接著介紹了高級數(shù)據(jù)結(jié)構(gòu)——樹狀數(shù)組的兩個基本操作——查詢前綴和與單點(diǎn)增加,最后介紹了樹狀數(shù)組的一個應(yīng)用——求解逆序?qū)?shù)。

lowbit(低位)運(yùn)算

定義為非負(fù)整數(shù) 在二進(jìn)制表示下 “最低位的 1 及其后邊所有的 0” 構(gòu)成的數(shù)值。

比如:

,其二進(jìn)制表示為 ,則其低位

公式

如何計算一個整數(shù)

中二進(jìn)制表示下所有位是 1 的數(shù)值?

比如

,則其二進(jìn)制表示下所有位是 1 的數(shù)值有: , 。

樸素算法需要枚舉整數(shù)中所有的位,時間復(fù)雜度為

, 為整數(shù) 的二進(jìn)制表示下的位數(shù)。

為了高效獲取二進(jìn)制表示下所有位是 1 的數(shù)值,可以利用

運(yùn)算,得到時間復(fù)雜度 , 為二進(jìn)制表示下為 1 的位的個數(shù)。

比如

, ;接著令 ,則 ;接著令 ,停止。

為了得到

的第幾位為 1,可以對 2 和 8 分別取對數(shù),即 , 。由于 C++ math.h 庫的 函數(shù)是以 為底的實(shí)數(shù)運(yùn)算,并且復(fù)雜度常數(shù)較大,所以可以通過預(yù)處理,利用哈希表來代替 運(yùn)算。

代碼

C++ 實(shí)現(xiàn)

const MAX_N = 1 << 20; int H[MAX_N + 1]; for (int i = 0; i <= 20; ++i) H[1 << i] = i; while (cin >> n) {while (n > 0) {cout << H[n & -n] << ' ';n -= n & -n;}cout << endl; }

樹狀數(shù)組

假設(shè)整數(shù)

,其二進(jìn)制表示形式為:

代表二進(jìn)制表示下位為 1 的索引下標(biāo)值,且假設(shè) 。

那么,可以將區(qū)間 [1,n] 劃分成

個小區(qū)間。
  • ...

比如,

,那么 區(qū)間可以劃分成 , 和 ,其區(qū)間長度分別為 , 和 。

利用

運(yùn)算計算區(qū)間:

C++ 實(shí)現(xiàn)

while (x > 0) {printf("[%d, %d]n" x - lowbit(x) + 1, x);x -= lowbit(x); }

樹狀數(shù)組是基于以上思想的數(shù)據(jù)結(jié)構(gòu),基本用途是維護(hù)序列的前綴和。

那么,假設(shè)有序列

,現(xiàn)在的問題就是如何將這個序列劃分成 個小區(qū)間。不妨,利用序列的索引值(以 1 為起點(diǎn)開始計數(shù)),根據(jù)上述計算區(qū)間的方式,將其以如下樹形結(jié)構(gòu)展開。

樹狀數(shù)組(Binary Indexed Tree) 以樹形結(jié)構(gòu)展開的序列 A

此時,以樹形結(jié)構(gòu)展開的序列 A 中的每一個節(jié)點(diǎn)都對應(yīng)著樹狀數(shù)組中的一個值。那么這個值為以當(dāng)前節(jié)點(diǎn)為根的子樹中所有節(jié)點(diǎn)值的總和。

接著,我們看下以樹形結(jié)構(gòu)展開的樹狀數(shù)組是什么樣的。

以樹形結(jié)構(gòu)展開的樹狀數(shù)組(Binary Indexed Tree)
  • Index 代表序列 A 中元素的索引,為了方便,以 1 為起點(diǎn)計數(shù)
  • Original Value 代表序列 A 中的元素值
  • BIT Value(Binary Indexed Tree Value)代表樹狀數(shù)組中的值
  • Binary bit 代表索引值的二進(jìn)制形式
  • Low bit 代表索引值的二進(jìn)制形式下的地位

上圖中最大的區(qū)別是某些節(jié)點(diǎn)中的值發(fā)生了變化。這是因為,在以樹形結(jié)構(gòu)展開的樹狀數(shù)組中的每一個值代表的是一個區(qū)間的總和。這個區(qū)間即為我們上述求解的區(qū)間,比如一個整數(shù) 7,可以將其劃分成

, 和 三個小區(qū)間。那么,這三個小區(qū)間的右端值作為索引對應(yīng)的樹狀數(shù)組中的值即為當(dāng)前區(qū)間元素的總和。

比如

對應(yīng)的樹狀數(shù)組的值為(BIT Value)10,它代表 這個區(qū)間的和。

再比如

對應(yīng)的樹狀數(shù)組的值為 11,它代表 這個區(qū)間的和。

基本操作

樹狀數(shù)組支持兩個基本操作——查詢前綴和,單點(diǎn)增加。

查詢前綴和

在尋求序列 A 的前 n 項的前綴和時,等于

代表的 個區(qū)間的總和。

C++ 實(shí)現(xiàn)

int query(int x) {int ans = 0;for (; x; x -= x & -x) ans += bit[x];return ans; }

單點(diǎn)增加

觀察父子節(jié)點(diǎn)的關(guān)系,可以推算出,父節(jié)點(diǎn)的索引 parent(i),為其子節(jié)點(diǎn)索引值 + 其低位——

.

C++ 實(shí)現(xiàn)

void update(int x, int delta) {for (; x; x += x & -x) bit[x] += delta; }

關(guān)于查詢前綴和與單點(diǎn)增加的計算過程,可以觀看下面視頻展示的動畫。

樹狀數(shù)組與逆序?qū)?/h2>

對于一個序列

,如果 ,并且 ,那么則稱 與 構(gòu)成逆序?qū)Α@脴錉顢?shù)組數(shù)據(jù)結(jié)構(gòu)可以求解序列 中的逆序?qū)€數(shù)。
  • 逆序遍歷序列
  • 利用樹狀數(shù)組的性質(zhì),使用 操作獲取每一個元素的逆序?qū)?shù)
  • 將當(dāng)前元素更新 到樹狀數(shù)組中
  • 循環(huán)迭代上述步驟,直到遍歷所有元素
  • C++ 實(shí)現(xiàn)

    int cnt = 0; for (int i = A.size() - 1; i >= 0; --i) {cnt += query(A[i]);update(A[i], 1); }

    在每一次更新

    樹狀數(shù)組時,以元素的值作為樹狀數(shù)組的索引,更新的值為 +1,代表個數(shù)。

    在每一次獲取

    逆序?qū)?shù)時,存在于樹狀數(shù)組中的元素的索引值都比當(dāng)前元素的大(逆序遍歷),那么自然獲取到的樹狀數(shù)組的值即為索引值比當(dāng)前元素的大,且值比當(dāng)前元素的小的個數(shù)。

    注意,上述的求解過程時,如果序列A的值范圍較大時,那么需要離散化處理。

    參考

    • 《算法競賽進(jìn)階指南》
    • 維基百科——樹狀數(shù)組

    本文作者:胡小旭

    聲明:本文歸作者版權(quán)所有,如需轉(zhuǎn)載請聯(lián)系。文中圖片和視頻為作者“胡小旭”制作,未經(jīng)允許嚴(yán)禁修改和翻版使用。

    總結(jié)

    以上是生活随笔為你收集整理的js 数组 实现 完全树_算法和数据结构 | 树状数组(Binary Indexed Tree)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。