傳說,有一種排序二叉樹叫做treap。
而 treap = tree + heap
所以,treap既具有樹,也具有堆的性質。
它的基本操作和普通的樹相近,但也有一些差異。
(以上全部為亂講系列)
(如果要看詳細介紹,這裡給出lmy大神關於平衡樹的研究講解
(詳細介紹之後會補充的)
首先,它的儲存方式和其他的二叉樹類似,都有關於該點以及它的子樹的儲存資訊。我們用 val 儲存每個點的點權,rnd (rd) 儲存每個點擁有的隨機優先順序,這樣我們就可以在之後利用堆的性質對其加以排序。同時我們也要記錄這個樹所包含的所有子樹以及它自己的大小,用 size 來表示。如果乙個點可以被多次建立,那麼我們還需要用 weight (wei) 來儲存當前點有多少是「重複」的 (即:這個點被重複插入了多少次)。
struct treap
int comp (int x)
void maintain ()
};treap *root = null;
接下來是它的兩個基本操作,插入和刪除。
那麼問題來了:如何對其進行旋轉操作呢?這裡我們給出了一種方法。至於實現圖例,本人還沒有新增,先看**。
void rotate(treap *&t, int d)
void ins(treap *&t, int v) else else
}t->maintain();
}}void del(treap *&t,int v) else else
if (t->s[1] == null) else
}} else
if (t != null) //防止刪空
t->maintain();
}
那麼,這裡的基本修改操作已經介紹完了。
所以,如何查詢treap裡面的某些特定元素(某乙個數的排名,處於某乙個排名的數,某個特定的數的前驅/後繼)?
這裡我們就要用到堆的性質。
我們以查詢乙個數 k 的排名為例子,當 k 的值大於當前節點時,即搜尋它的右子節點,同時加上該節點和它的左子樹的 size 值(表示它的名次)。當 k 的值小於當前節點時,即搜尋它的左子樹,此時不加任何 size 值(k 的排名會在前面)。當 k 的值與當前節點相等時,返回 rank+1(名次要包括當前節點)。
其他的查詢方式與上述思想相似,這裡不再贅述。看**就能懂了。
int query_rank(treap *t, int v)
//如果這個位置沒有左子樹,那麼,這個數的相對名次(相對於這棵子樹而言)為0,返回的名次值就應為1
else
//返回所有左子樹的size值,名次也對應地增加這麼多
if (d == -1) else
if (d == 1) else
}int query_kth(treap *t, int k) else else
if (k > t->s[0]->size && k <= p) else
}}int query_prev(treap *t, int v, int m) else
}int query_next(treap *t, int v, int m) else
}
至此,我們已經明白了所有的操作方式。
下面貼上完整的**:
Treap原理和實現方法
分類 資料結構 2013 09 07 14 11 320人閱讀收藏 舉報treap是一棵二叉搜尋樹,只是每個節點多了乙個優先順序fix,對於每個節點,該節點的優先順序小於等於其所有孩子的優先順序。當然,引入優先順序fix的目的就是防止bst退化成一條鏈,從而影響查詢效率。所以,這樣看來就是 trea...
Treap實現的名次樹
1.感覺之前邵叔叔教的做fib的那個支援刪除 其實刪除只是打標記,而且不支援插入。和查詢的排序二叉樹就是個靜態的名次樹嘛。我居然學到了這麼奇怪的資料結構。2.寫的時候坑了幾次 1 不要亂用引用,getkth裡那個引數o沒過腦子用了引用,結果把樹搞爛了,一堆ch x 賦值成null了。2 寫查詢的時候...
並查集 treap實現名次數 BZOJ2733
time limit 10 sec memory limit 128 mb submit 1351 solved 710 submit status 永無鄉包含 n 座島,編號從 1 到 n,每座島都有自己的獨一無二的重要度,按照重要度可 以將這 n 座島排名,名次用 1 到 n 來表示。某些島之間...