定義
數(shù)堆名字取了Tree和Heap各一半,即Treap,是二叉搜索樹(shù)和堆合并構(gòu)成的數(shù)據(jù)結(jié)構(gòu)。而堆和二叉搜索樹(shù)的性質(zhì)是有沖突的,二叉搜索樹(shù)滿足左子樹(shù)<根節(jié)點(diǎn)<右子樹(shù),而堆是滿足根節(jié)點(diǎn)小于等于(或大于等于)左右子樹(shù)。因此在Treap的數(shù)據(jù)結(jié)構(gòu)中,并不是以單一的鍵值作為節(jié)點(diǎn)的數(shù)據(jù)域。Treap每個(gè)節(jié)點(diǎn)的數(shù)據(jù)域包含2個(gè)值,key和weight。key值,和原來(lái)的二叉搜索樹(shù)一樣,滿足左子樹(shù)<根節(jié)點(diǎn)<右子樹(shù)。weight值在Treap中滿足堆的性質(zhì),根節(jié)點(diǎn)的weight值小于等于(或大于等于)左右兒子節(jié)點(diǎn)。
示例Treap:
代碼實(shí)現(xiàn)為:
struct Node
{
int key;
int weight;
Node * lchild;
Node * rchild;
Node * father;
}Node;
旋轉(zhuǎn)操作
Treap大部分操作和二叉搜索樹(shù)是一樣的,區(qū)別是插入操作時(shí)weight值可能會(huì)不滿足堆的性質(zhì),這時(shí)需要進(jìn)行旋轉(zhuǎn)操作
示例:
右兒子節(jié)點(diǎn)是新插入的,并不滿足堆的性質(zhì),所以要對(duì)其進(jìn)行調(diào)整,假設(shè)這個(gè)Treap滿足小根堆的性質(zhì),則調(diào)整結(jié)果為
這樣最小的weight值就位于根節(jié)點(diǎn)處。這個(gè)操作叫做旋轉(zhuǎn)。
- 將右兒子調(diào)整至根部的旋轉(zhuǎn)叫做左旋
- 將左兒子調(diào)整至根部的旋轉(zhuǎn)叫做右旋
左旋操作
操作過(guò)程:
- 獲取根節(jié)點(diǎn)A的右兒子節(jié)點(diǎn)B
- 將節(jié)點(diǎn)B的父親節(jié)點(diǎn)信息更新為f,并更新節(jié)點(diǎn)f的子節(jié)點(diǎn)信息為B
- 將節(jié)點(diǎn)A的右兒子信息更新為節(jié)點(diǎn)B的左兒子D,同時(shí)將節(jié)點(diǎn)D的父親節(jié)點(diǎn)信息更新為A
- 將節(jié)點(diǎn)B的左兒子信息更改為節(jié)點(diǎn)A,同時(shí)將節(jié)點(diǎn)A的父親節(jié)點(diǎn)信息更改為B
代碼實(shí)現(xiàn)為
void LeftRotate( Node &*A )
{
// step1
Node *B=A->rchild;
// step2
B->father=A->father;
if( A->father->lchild == A )
B->father->lchild=B;
else
B->father->rchild=B;
// step3
if( B->lchild!=NULL )
{
A->rchild=B->lchild;
B->lchild->father=A;
}
// step4
A->father=B;
B->lchild=A;
}
右旋操作
其操作是左旋的鏡像
- 獲取根節(jié)點(diǎn)A的左兒子節(jié)點(diǎn)B
- 將節(jié)點(diǎn)B的父親節(jié)點(diǎn)信息更新為f,并更新節(jié)點(diǎn)f的子節(jié)點(diǎn)信息為B
- 將節(jié)點(diǎn)A的左兒子信息更新為節(jié)點(diǎn)B的右兒子D,同時(shí)將節(jié)點(diǎn)D的父親節(jié)點(diǎn)信息更新為A
- 將節(jié)點(diǎn)B的右兒子信息更改為節(jié)點(diǎn)A,同時(shí)將節(jié)點(diǎn)A的父親節(jié)點(diǎn)信息更改為B
代碼實(shí)現(xiàn)為
void RightRotate( Node &*A )
{
// step1
Node *B=A->lchild;
// step2
B->father=A->father;
if( A->father->lchild == A )
B->father->lchild=B;
else
B->father->rchild=B;
// step3
if( B->rchild!=NULL )
{
A->lchild=B->rchild;
B->rchild->father=A;
}
// step4
A->father=B;
B->lchild=A;
}
總結(jié)
數(shù)堆的優(yōu)勢(shì)為:對(duì)于一般的二叉搜索樹(shù),在某些特殊情況下根據(jù)輸入數(shù)據(jù)來(lái)建樹(shù)有可能退化為一條鏈,比如一個(gè)依次增大的數(shù)列。而如果一棵二叉排序樹(shù)的節(jié)點(diǎn)是按照隨機(jī)順序插入,得到的二叉排序樹(shù)大多數(shù)情況下是平衡的,其期望高度是O(logn)。因此Treap利用weight值作為隨機(jī)因子來(lái)調(diào)整二叉樹(shù)的形狀,使得在大部分情況下比直接通過(guò)數(shù)據(jù)建立的二叉樹(shù)要平衡。
每一次查找的期望復(fù)雜度也會(huì)降低,總體的速度也就得到了提高。