利用伸展树提高区间操作的性能
一、首先,什么是區間操作?以及各種數據結構性能對比
區間操作就是對一個序列的某個區間的所有元素進行的操作。比如,對區間所有元素增加一個值,翻轉區間元素等。
對區間操作,最普通的方法就是數組。比如:對一個長為N 的序列的 [L,R]區間執行每個元素加上k 的操作,可以使用數組來保存序列,然后使用循環對[L,R]區間每個元素加k 。
代碼是這樣的:
這樣做的效率是 O(N),對于一個排序來說這是很好的性能,但對于一個操作來說,這并不是理想,很多二叉樹的操作都能達到O( log N) 級別。
對于最典型的查找操作,普通二叉樹的操作能達到O( log N) ,但是樹在最壞情況下性能會退化到O(N)(比如順邊的情況下) 。
平衡樹能對樹高度進行控制,最壞性能控制在O(log N),但是,平衡樹只是控制了樹的高度,而不能保證訪問頻率高的節點離跟越近,因此,平衡樹的訪問效率與節點的分布有關,如果訪問頻率高的節點離根很遠,那么平衡樹的性能就會有所降低。
因此,便有了伸展樹。伸展樹的特點就是:每次查找或插入節點,都會把該節點旋轉到樹根位置,隨著操作次數增加,高頻節點就會聚集在根周圍,從而達到較好的性能。
二、伸展樹介紹
伸展樹的特點就是:每次查找或插入節點,都會把該節點旋轉到樹根位置,隨著操作次數增加,高頻節點就會聚集在根周圍,從而達到較好的性能。
伸展樹首先是一棵樹,可以定義如下:
typedef struct Node {int key; struct Node *lch,*rch,*parent; }* Node ,* Tree;伸展樹的高層操作有:
| insert( t , x ) | 將x插入t中。找到x在t中的位置,插入x,然后再將x旋轉到樹根 |
| delete( t ,x ) | 刪除x。找到x,將x調到根部,將x的左子樹和右子樹刪除后合并。 |
| spilt( t , x) | 以x為界分離t。找到x,將x旋轉到樹根,然后將x的左子樹和剩余部分分離 |
| find( t , x ) | 找到x。找到x,然后將x旋轉到樹根。 |
| join( t1 , t2 ) | 合并子樹 t1和t2,要求t1所有元素小于t2的任一元素。找到t1的最大元素,并調整到根部,將t2作為根的右子樹插入 |
可見,樹的高層操作都依賴與旋轉等基本操作:
| splay( t ,x ) | 將x調至根部。循環調用zig_zag_manager( t , x) 方法,直到x == t |
| zig_zag_manager( t , x) | 旋轉管理者。 找到x,分析x與父親節點,父親節點與祖父節點的關系,選擇恰當的旋轉方式。 |
| 下面幾個函數中,設x 的父節點為 p, p的父節點為g 。 | |
| zig( t , x ) | 右旋。當p是根節點,x是p的左孩子,將x右旋 |
| zag( t , x ) | 左旋。當p是根節點,x是p的右孩子,將x左旋 |
| zig_zig( t , x ) | 右雙旋。x是p的左節點,當p是g的左節點,先將p右旋,再將x右旋 |
| zag_zag( t , x ) | 左雙旋。x是p的右節點,當p是g的右節點,先將p左旋,再將x左旋 |
| zig_zag( t , x ) | 右旋再左旋。x是p的左節點,當p是g的右節點,先將x右旋,再將x左旋 |
| zag_zig( t , x ) | 左旋再右旋。x是p的右節點,當p是g的左節點,先將x左旋,再將x右旋 |
其實上述左旋和右旋很有規律,當一個節點是左節點時,應當右旋,當一個節點是右節點時,應當左旋。
伸展樹的區間操作
伸展樹操作區間的思路是:
第一步,分離區間。分離長度為N的序列里的區間 [L ,R ],首先找到第L大的元素,然后以其為界進行分離操作,得到t1 = [0,L-1] 和 temp = [L ,N]。
然后,再找到 temp 中第 R-L+1 大元素,并以該元素為界進行分離操作, 得到 t2 = [L ,R] 和 t3 = [R+1, N]。這樣,就成功分離出了目標區間t2 。
第二步,對目標區間進行操作。
第三步,合并區間。合并t1,t2,t3。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的利用伸展树提高区间操作的性能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php正则表达式函数案例,PHP正则表达
- 下一篇: 什么是取消外资股比限制?有什么影响?