首先要知道左偏樹是用來幹什麼的。如果給我們兩個優先序列,然後讓我把這兩個優先佇列合併成乙個優先佇列。如果直接用堆,就是將乙個佇列裡面的數不斷彈出然後扔到另乙個佇列裡。複雜度是\(o(n)\)n為佇列中數的個數。但是用左偏樹就可以做到\(log(n_1 + n_2)\)。
ps:為了便於討論,本文所有的左偏樹均已小根樹為例。
外節點: 至少乙個兒子為空的節點稱為外節點。
距離: 某個節點的距離定義為這個節點到他的子樹中離他最近的那個外節點的距離。這個的作用讀完全文可能就明白了。
性質1:任何乙個節點的兒子一定比這個節點的數小。
性質2:任何乙個節點的左兒子的距離一定大於等於右兒子的距離
性質3:任何乙個節點的距離等於他的右兒子的距離+1。(空節點的距離為-1)
性質4:一棵n個節點的左偏樹中,距離最大的節點的距離不超過\(log(n + 1) -1\)
繼續考慮一開始那個合併兩個優先佇列的問題。首先我們肯定不想乙個乙個的加入佇列。而是最好可以通過改變一些節點的兒子,來使得左偏樹的性質得到維護。
那麼左偏樹是怎麼實現的呢?
如圖
既然叫左偏樹,那麼就比較偏向左邊嘛。所以每次加入的時候都只想改變右孩子。
我們現在要合併上面兩顆左偏樹。
1:先比較兩棵樹的根節點。發現第一棵樹比較小,所以就考慮將第二棵樹加到第一棵樹的右子樹上去。所以就遞迴的合併第二棵子樹和第乙個子樹的右子樹。並且合併後的根作為1號節點的右兒子。
2:發現2號節點比4號節點小,所以1號節點的右兒子變為2,然後繼續合併2號節點的右子樹和以4為根節點的子樹。
3:發現4比5小,所以把2號節點的右兒子變為4,然後合併4號節點的右兒子和5號節點。
4:發現4號節點右兒子為空,返回
5:維護左偏樹的性質,更新每個結點的距離。並且如果左兒子的距離比右兒子要小,那麼就交換兩個兒子。
最終得到一棵這樣的左偏樹
這時就要說到距離的用處了。既然有性質2,那麼與右兒子合併肯定比與左兒子合併更早結束遞迴(因為結束遞迴的時刻是當發現要合併的兩個節點是外節點的時候)。
合併操作
上面已經說了
刪除操作
將根的左右兒子都變為零,然後將左右子樹合併起來就行了。
插入操作
插入乙個幾點就相當於插入乙個只有乙個節點的左偏樹
洛谷3377
時間再拉長一點,讓我有時間收拾一下心情。 ——火影忍者
左偏樹學習筆記
左偏樹是一種基於二叉樹的可並堆。定義乙個節點的 距離 dis xdis x disx 為它到空節點的最短路長度,左偏樹強制要求 dis lson dis rson dis ge dis dislso n d isrs on 所以 dis x di srso n 1dis x dis 1 disx d...
學習筆記 左偏樹
左偏樹是一種可並堆,除了堆的基本功能,最大的特點就是支援合併堆,甚至比普通堆好寫。下面敘述以小根堆為例,大根堆對稱。o log n 求乙個數所在堆的根 o 1 求最小值 o log n 合併兩個堆 o log n 刪除最小值 o log n 插入乙個數 n 是插入的總節點數 或當前堆的節點數 str...
左偏樹 學習筆記
左偏樹是可並堆的一種。除了支援堆的所有操作之外,左偏樹還支援合併兩個堆並把複雜度維持在 o n log n 級別。dist 外節點 對於一棵二叉樹,我們定義外節點為左兒子或右兒子為空的節點。dist 我們定義某乙個節點的 text 為該點到最近的外節點的距離。外節點的 text 為 1 我們不難發現...