【數(shù)據(jù)結(jié)構(gòu)】線段樹

【數(shù)據(jù)結(jié)構(gòu)】線段樹

老規(guī)矩,簡書 Makedown 兼容性差咳秉。附上 CSDN 的 【數(shù)據(jù)結(jié)構(gòu)】線段樹

問題

最后一次用到線段樹爽蝴,是在深圳老東家實(shí)習(xí)面試的時候春宣,Jason 問到我的一個問題(具體問題不記得了,大致意思):

  • 一個固定大小 n 的有限數(shù)組 x
  • action 1 : 可以隨時更新某個區(qū)間 [i, j] 內(nèi)的元素
  • action 2 : 可以查詢某個區(qū)間 [i, j] 內(nèi)的最大值或最小值

你應(yīng)該如何做衙熔?

簡單的解法 1 登颓?

普通數(shù)組形式存儲,額外空間消耗 O\left(1\right)红氯,總共空間復(fù)雜度 O\left(n\right) .

action 1 : 遍歷區(qū)間[i, j]框咙,進(jìn)行元素的更新,時間復(fù)雜度 O\left(n\right) .

action 2: 遍歷區(qū)間 [i, j]痢甘,查找最大值或最小值喇嘱,時間復(fù)雜度 O\left(n\right) .

顯然這種形式對于有大量查詢操作的情況下,耗時會很嚴(yán)重塞栅。

這時可以采用線段樹進(jìn)行處理者铜。

線段樹

時間復(fù)雜度和空間復(fù)雜度

需要預(yù)處理生成線段樹。

預(yù)處理耗時:O\left(n\right)

總共空間復(fù)雜度:O\left(n\log n\right)

區(qū)間更新時間復(fù)雜度:O\left(\log n\right)

區(qū)間查詢時間復(fù)雜度:O\left(\log n\right)

創(chuàng)建線段樹

線段樹采用二叉樹形式存儲:

  • 葉子節(jié)點(diǎn)對應(yīng)原始數(shù)組 x 中的元素放椰。
  • 非葉子節(jié)點(diǎn)表示它所有子孫葉子節(jié)點(diǎn)所在區(qū)間的最值作烟。

假設(shè)數(shù)組 x 為:x = [ 2, 5, 1, 4, 9, 3 ] ,一共 n=6 個元素庄敛。

那么需要構(gòu)建的線段樹:

graph TD;
    A(區(qū)間 0-5 min: 1)-->B;
    A-->C;
    B(區(qū)間 0-2 min: 1)-->D;
    B-->E((1));
    C(區(qū)間 3-5 min: 3)-->F;
    C-->G((3));
    D(區(qū)間 0-1 min: 2)-->H((2));
    D-->I((5));
    F(區(qū)間 3-4 min: 4)-->J((4));
    F-->K((9));

注意構(gòu)建的時候俗壹,在非葉子節(jié)點(diǎn)更新你想要存儲的區(qū)間信息(區(qū)間最大值,區(qū)間最小值等)藻烤。

區(qū)間查詢

查詢 [1, 4] 內(nèi)的最小值

  1. 第一步:找到區(qū)間范圍內(nèi)的最下層節(jié)點(diǎn):
graph TD;
    A(區(qū)間 0-5 min: 1)-->B;
    A-->C;
    B(區(qū)間 0-2 min: 1)-->D;
    B-->E((1 *));
    C(區(qū)間 3-5 min: 3)-->F;
    C-->G((3));
    D(區(qū)間 0-1 min: 2)-->H((2));
    D-->I((5 *));
    F(區(qū)間 3-4 min: 4 *)-->J((4));
    F-->K((9));

圖中標(biāo)記 * 號的節(jié)點(diǎn)為當(dāng)前需要查詢的節(jié)點(diǎn)绷雏。

為什么查詢的最下層是節(jié)點(diǎn)头滔?而不是葉子節(jié)點(diǎn)?(請注意看 [3, 4] 區(qū)間涎显,不需要查詢其葉子節(jié)點(diǎn))

按道理每個區(qū)間范圍內(nèi)的葉子節(jié)點(diǎn)都需要更新坤检。

  • 線段樹每個節(jié)點(diǎn)管理的都是一個區(qū)間(葉子節(jié)點(diǎn)管理的區(qū)間內(nèi)只有一個元素)
  • 我們知道每個劃分出來的區(qū)間的最小值
  • 如果區(qū)間查詢的范圍 [i, j] 完全包含其中一個區(qū)間 [ik, jk]i <= ik <= jk <= j
  • 顯然這個區(qū)間 [ik, jk] 的最小值就是當(dāng)前值
  • 無需再繼續(xù)往下查詢

[1, 4] 區(qū)間包含的節(jié)點(diǎn)是:1-1, 2-2, 3-4

  1. 第二步:遞歸向上查詢最小值

對應(yīng)的最小值分別為:x[1,1]=5, x[2,2]=1, x[3,4]=4

從上到下查找的過程(遞歸)示例期吓,用 xij 表示區(qū)間 x[i, j] 的值:


min(x14) = min(x12, x34)
         = min(min(x11, x22), 4)
         = min(min(5, 1), 4)
         = min(1, 4)
         = 1

區(qū)間更新

更新 [1, 4] 之間所有元素加 3早歇。

  1. 第一步:找到需要更新的最下層節(jié)點(diǎn)
graph TD;
    A(區(qū)間 0-5 min: 1)-->B;
    A-->C;
    B(區(qū)間 0-2 min: 1)-->D;
    B-->E((1 *));
    C(區(qū)間 3-5 min: 3)-->F;
    C-->G((3));
    D(區(qū)間 0-1 min: 2)-->H((2));
    D-->I((5 *));
    F(區(qū)間 3-4 min: 4 *)-->J((4));
    F-->K((9));

圖中標(biāo)記 * 號的節(jié)點(diǎn)為當(dāng)前需要更新的節(jié)點(diǎn)。

范圍同上讨勤。

同理:

  • 我們知道每個區(qū)間的最小值
  • 如果區(qū)間更新的范圍 [i, j] 完全包含其中一個區(qū)間 [ik, jk]i <= ik <= jk <= j
  • 顯然這個區(qū)間 [ik, jk] 的最小值就是當(dāng)前值 + 變更值
  • 無須繼續(xù)向下更新
  1. 第二部:遞歸向上更新區(qū)間

遞歸往上更新后的結(jié)果為:

graph TD;
    A(區(qū)間 0-5 min: 2 *)-->B;
    A-->C;
    B(區(qū)間 0-2 min: 2 *)-->D;
    B-->E((4 *));
    C(區(qū)間 3-5 min: 3 *)-->F;
    C-->G((3));
    D(區(qū)間 0-1 min: 2 *)-->H((2));
    D-->I((8 *));
    F(區(qū)間 3-4 min: 7 #)-->J((4));
    F-->K((9));

圖中標(biāo)記 *# 號的節(jié)點(diǎn)為更新過程中需要更新最小值的節(jié)點(diǎn)箭跳。

等等,是不是有點(diǎn)不對勁潭千?

還是 [3, 4] 這區(qū)間谱姓。[3, 4] 完全處于 [1, 4] 的更新范圍內(nèi),在更新時無需更新其所有子節(jié)點(diǎn)刨晴。

但是按照上圖的結(jié)果屉来,如果我進(jìn)行查詢 [3, 3] 的最小值(或者更新值)。顯然結(jié)果與圖示的數(shù)據(jù)不符合狈癞。

所以需要增加更新標(biāo)志位茄靠,處理上面所提及的情況。

graph TD;
    A(區(qū)間 0-5 min: 2)-->B;
    A-->C;
    B(區(qū)間 0-2 min: 2)-->D;
    B-->E((4));
    C(區(qū)間 3-5 min: 3)-->F;
    C-->G((3));
    D(區(qū)間 0-1 min: 2)-->H((2));
    D-->I((8));
    F(區(qū)間 3-4 min: 7 # +3)-->J((4));
    F-->K((9));

該標(biāo)志位記錄當(dāng)前區(qū)間的變更值蝶桶。

在進(jìn)行涉及該區(qū)間的子節(jié)點(diǎn)查詢 / 更新時慨绳,需要取出該值遞歸更新沿途的區(qū)間。

查詢 [3, 3]

graph TD;
    A(區(qū)間 0-5 min: 2)-->B;
    A-->C;
    B(區(qū)間 0-2 min: 2)-->D;
    B-->E((4));
    C(區(qū)間 3-5 min: 3)-->F;
    C-->G((3));
    D(區(qū)間 0-1 min: 2)-->H((2));
    D-->I((8));
    F(區(qū)間 3-4 min: 7 # 0)-->J((7 *));
    F-->K((12 # +3));

其中 * 號為更新后的值莫瞬,# 號為傳遞的標(biāo)志位儡蔓。

在更新了區(qū)間后,需要把原有的 [3, 4] 標(biāo)志位清除(否則下次會導(dǎo)致重復(fù)更新)疼邀。

區(qū)間 [4, 5] 所有元素 -2

在查詢 [3, 3] 進(jìn)行這一步操作

graph TD;
    A(區(qū)間 0-5 min: 2)-->B;
    A-->C;
    B(區(qū)間 0-2 min: 2)-->D;
    B-->E((4));
    C(區(qū)間 3-5 min: 3)-->F;
    C-->G((3 *));
    D(區(qū)間 0-1 min: 2)-->H((2));
    D-->I((8));
    F(區(qū)間 3-4 min: 7 # +3)-->J((4));
    F-->K((9 *));

其中 * 號的為需要更新的最底層節(jié)點(diǎn)喂江。

graph TD;
    A(區(qū)間 0-5 min: 2)-->B;
    A-->C;
    B(區(qū)間 0-2 min: 2)-->D;
    B-->E((4));
    C(區(qū)間 3-5 min: 3)-->F;
    C-->G((3 -2 *));
    D(區(qū)間 0-1 min: 2)-->H((2));
    D-->I((8));
    F(區(qū)間 3-4 min: 7 # 0)-->J((7 # +3));
    F-->K((9 +3-2 *));

把區(qū)間標(biāo)志位和變更值一起傳遞(注意區(qū)間范圍),同時清除已經(jīng)更新完的區(qū)間標(biāo)志位旁振。

結(jié)果:

graph TD;
    A(區(qū)間 0-5 min: 1)-->B;
    A-->C;
    B(區(qū)間 0-2 min: 2)-->D;
    B-->E((4));
    C(區(qū)間 3-5 min: 1)-->F;
    C-->G((1));
    D(區(qū)間 0-1 min: 2)-->H((2));
    D-->I((8));
    F(區(qū)間 3-4 min: 7)-->J((7));
    F-->K((10));
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末获询,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子拐袜,更是在濱河造成了極大的恐慌吉嚣,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蹬铺,死亡現(xiàn)場離奇詭異尝哆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)甜攀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門秋泄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來琐馆,“玉大人,你說我怎么就攤上這事恒序∈蒴铮” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵歧胁,是天一觀的道長滋饲。 經(jīng)常有香客問我,道長喊巍,這世上最難降的妖魔是什么屠缭? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮崭参,結(jié)果婚禮上勿她,老公的妹妹穿的比我還像新娘。我一直安慰自己阵翎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布之剧。 她就那樣靜靜地躺著郭卫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪背稼。 梳的紋絲不亂的頭發(fā)上贰军,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天,我揣著相機(jī)與錄音蟹肘,去河邊找鬼词疼。 笑死,一個胖子當(dāng)著我的面吹牛帘腹,可吹牛的內(nèi)容都是我干的贰盗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼阳欲,長吁一口氣:“原來是場噩夢啊……” “哼舵盈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起球化,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤秽晚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后筒愚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赴蝇,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年巢掺,在試婚紗的時候發(fā)現(xiàn)自己被綠了句伶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片劲蜻。...
    茶點(diǎn)故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖熄阻,靈堂內(nèi)的尸體忽然破棺而出斋竞,到底是詐尸還是另有隱情,我是刑警寧澤秃殉,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布坝初,位于F島的核電站,受9級特大地震影響钾军,放射性物質(zhì)發(fā)生泄漏鳄袍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一吏恭、第九天 我趴在偏房一處隱蔽的房頂上張望拗小。 院中可真熱鬧,春花似錦樱哼、人聲如沸哀九。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽阅束。三九已至,卻和暖如春茄唐,著一層夾襖步出監(jiān)牢的瞬間息裸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工沪编, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留呼盆,地道東北人。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓蚁廓,卻偏偏與公主長得像访圃,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子纳令,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容