旋转Treap的简单实现

Treap=Tree+Heap

Treap是一棵二叉搜索树,它的左子树和右子树分别是一个Treap,和一般的二叉搜索树不同的是,Treap结构中每个节点x有两个域,一个是其关键字值key,一个是优先级数priority(他是一个独立选取的随机数),对于Treap结构,其关键字遵循二叉搜索树性质,其优先级遵循堆性质。但是这里要注意的是Treap和二叉堆有一点不同,就是二叉堆必须是完全二叉树,而Treap可以并不一定是。

在这里用的链表实现的旋转的Treap,简单实现是思路比较简单,但代码稍微有点繁琐。有点懒,不想整理了。

TreapNode结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
template<class T>
struct treapNode
{
int key;//用于二叉搜索树的关键字
int pri;//用于堆性质的优先级数字
T element;//其中的元素
treapNode<T> *leftChild, //左子树
*rightChild,
*father; //右子树
treapNode() {leftChild = rightChild = father=NULL;}//构造函数
treapNode(const T& theElement):element(theElement)
{
leftChild = rightChild = father=NULL;
}
treapNode(const T& theElement,
treapNode *theLeftChild,
treapNode *theRightChild,
treapNode *theFather)
:element(theElement)
{
leftChild = theLeftChild;
rightChild = theRightChild;
father=theFather;
}
treapNode(int theKey,int thePri,T theElement)
{
key=theKey;
pri=thePri;
element=theElement;
leftChild = rightChild = father=NULL;
}
treapNode(int theKey,T theElement)
{
key=theKey;
pri=rand();
element = theElement;
leftChild=rightChild=father=NULL;
}
};

在节点中加入了父节点的指针,为了后面的旋转操作能够更简单一点,不加也是可以的,不过就要稍微复杂一点了。

插入操作:

不满足:当插入的节点为其父节点的左孩子时,应该右旋,否则左旋。

插入方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
template<class T>
void treap<T>::insert(treapNode<T> *t)//插入方法,参数为一个treap节点。
{ t->leftChild=t->rightChild=t->father=NULL;
if(root==NULL)//当treap为空的时候情况
{
root=t;
treapSize++;
return ;
}
else//当treap不为空的时候,要找到要删除的位置
{
treapNode<T> *pp=root;
treapNode<T> *p=NULL;
while(pp!=NULL)
{ p=pp;
if(t->key<pp->key)//小于关键字时
pp=pp->leftChild;
else
{
if(t->key>pp->key)//大于关键字时
pp=pp->rightChild;
else//要插入的节点已经重复时
{
pp->element=t->element;
treapSize--;
return;
}
}
}
if(t->key>p->key)
{
p->rightChild=t;
t->father=p;
}
else
{
p->leftChild=t;
t->father=p;
}
}
treapNode<T> *q=t->father;//获取插入节点的父节点
//treapNode<T> *w=t->father;
int com;//判断是否循环继续的量
do//采用do-while结构,保证循环至少进行一次
{ com=0;
if(t->pri<q->pri&&t->key<q->key)//当优先级不满足堆的性质并且插入的节点在左孩子的位置时,此时应该右旋
{ if(t->rightChild!=NULL)//当插入节点的右孩子不为空的时候
{
q->leftChild=t->rightChild;//插入节点的右孩子变成其父节点的左孩子
t->rightChild->father=q;//插入节点的右孩子的父母指向插入节点的父母
t->rightChild=q;//父节点变为插入节点的右孩子
if(q->father!=NULL)//在这里分情况讨论,当其父节点的父节点不为空的时候
{
t->father=q->father;//插入节点的父节点为其父节点的父节点
if(q->father->leftChild==q)//判断父节点是否是父节点的父节点的左孩子
q->father->leftChild=t;//父节点的父节点左孩子变成插入节点
else
q->father->rightChild=t;
q->father=t; //父节点的父母变成插入节点
}
else//当其父节点的父节点为空时
{
t->father=NULL;//插入节点的父节点为空
root=t;
q->father=t;//父节点的父母变为插入节点
}
}
else//当插入节点的右孩子为空的时候
{ t->rightChild=q;
if(q->father!=NULL)//当其父节点的父节点不为空时
{
t->father=q->father;
if(q->father->leftChild==q) //判断父节点是否是父节点的父节点的左孩子
q->father->leftChild=t;
else
q->father->rightChild=t;
q->father=t;
q->leftChild=NULL;
}
else//当其父节点的父节点为空时
{
t->father=NULL;//父节点变为空
root=t;//此时根节点为当前插入的节点
t->rightChild=q;//插入节点的右孩子变为原来节点的父节点
q->father=t; //插入节点的父节点改成当前节点
q->leftChild=NULL;//插入节点的原来的父节点改为空值
}
} com=1;
}
if(t->pri<q->pri&&t->key>q->key)//当优先级不满足堆的性质并且插入的节点在右孩子的位置时,此时应该左旋
{ if(t->leftChild!=NULL)//当插入节点的左孩子不为空的时候
{
q->rightChild=t->leftChild;//插入节点的左孩子变成其父节点的右孩子
t->leftChild->father=q;//插入节点的左孩子的父母指向插入节点的父母
t->leftChild=q;//父节点变为插入节点的左孩子
if(q->father!=NULL)//在这里分情况讨论,当其父节点的父节点不为空的时候
{
t->father=q->father;//插入节点的父节点为其父节点的父节点
if(q->father->leftChild==q)//判断父节点是否是父节点的父节点的左孩子
q->father->leftChild=t;//父节点的父节点左孩子变成插入节点
else
q->father->rightChild=t;
q->father=t; //父节点的父母变成插入节点

}
else//当其父节点的父节点为空时
{
t->father=NULL;//插入节点的父节点为空
root=t;
q->father=t;//父节点的父母变为插入节点
q->leftChild=NULL;
}
}
else//当插入节点的左孩子为空的时候
{ t->leftChild=q;
if(q->father!=NULL)//当其父节点的父节点不为空时
{
t->father=q->father;
if(q->father->leftChild==q) //判断父节点是否是父节点的父节点的左孩子
q->father->leftChild=t;
else
q->father->rightChild=t;
q->father=t;
q->rightChild=NULL;
}
else//当其父节点的父节点为空时
{
t->father=NULL;
root=t;
t->leftChild=q;
q->father=t;
q->rightChild=NULL;
}
} com=1;
}
q=t->father;//更新插入节点的父节点
} while(q!=NULL&&com==1);//
treapSize++;
}

删除操作:

先找到要删除的节点的位置,然后判断要删除的节点的有几个孩子,然后再根据情况具体实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
template<class T>
void treap<T>::erase(int key)
{
treapNode<T> *t=root;
while(t!=NULL)//首先找到要删除的节点
{
if(t->key<key)
t=t->rightChild;
else
{
if(t->key>key)
t=t->leftChild;
else//当相等时即找到要删除的节点了,跳出循环
break;
}
}
if(t==NULL)//treap中没有要删除的关键字的元素
{
cout<<"please put in correct data"<<key<<" ";
return ;
}
else//找到要删除的节点后
{
treapNode<T> *q=t->father;//找到要删除的节点的父节点
if(t->leftChild==NULL&&t->rightChild==NULL)//最简单的情况:当要删除的节点为叶节点时 ,并且此种情况下优先级的顺序不会改变
{
if(t==root)//其中的特殊情况:只有一个节点,即根节点
root=NULL;
else//不为根节点
{
if(key<q->key)//判断是左孩子还是右孩子
q->leftChild=NULL;
else
q->rightChild=NULL;
t->father=NULL;//让此节点的父节点为空
//t=NULL;//释放此节点
}
}
if((t->leftChild==NULL&&t->rightChild!=NULL)||(t->leftChild!=NULL&&t->rightChild==NULL))//当要删除的节点为有一个孩子时
{
if(q==NULL)//当要删除的节点为根节点时
{
if(t->leftChild!=NULL)//如果左孩子不为空
{ t->leftChild->father=NULL;
root=t->leftChild;
t->leftChild=NULL;
}
else//右孩子不为空
{
t->rightChild->father=NULL;
root=t->rightChild;
t->rightChild=NULL;
}
}
else//删除的节点不为根节点时
{
if(t->key<q->key)//当为其左孩子时
{
if(t->leftChild!=NULL)//当要删除的节点的左孩子不为空时
{
q->leftChild=t->leftChild;//删除节点的父节点的左孩子指向删除节点的左孩子
t->leftChild->father=q;//删除节点的左孩子的父亲指向删除节点的父亲
t->leftChild=NULL;//删除节点的左孩子指针指向空
t->father=NULL;//其父节点的指针指向空
}
else//当要删除的右孩子不为空时
{
q->leftChild=t->rightChild;
t->rightChild->father=q;
t->rightChild=NULL;
t->father=NULL;
}
}
else//当为其右孩子时
{
if(t->leftChild!=NULL)//当要删除的节点的左孩子不为空时
{
q->rightChild=t->leftChild;
t->leftChild->father=q;
t->leftChild=NULL;
t->father=NULL;
//t=NULL;
}
else//当删除的节点的右孩子不为空时
{
q->rightChild=t->rightChild;
t->rightChild->father=q;
t->rightChild=NULL;
t->father=NULL;
//t=NULL;
}
}
}
}
if(t->leftChild!=NULL&&t->rightChild!=NULL)//左右孩子均不为空的情况
{
if(t->leftChild->pri<t->rightChild->pri)//找出左右孩子中优先级较小的那个
{treapNode<T> *p=t->leftChild;//记录下当前节点的左孩子
if(p->rightChild==NULL)//当左孩子的右孩子为空时
{
if(q==NULL)//如果待删节点为根节点
{
p->rightChild=t->rightChild;
p->father=NULL;
t->rightChild->father=p;
t->leftChild=t->rightChild=NULL;
//t=NULL;
root=p;
}
else//待删节点不为根节点
{
p->rightChild=t->rightChild;
t->rightChild->father=p;
p->father=q;
if(q->leftChild==t)
q->leftChild=p;
else
q->rightChild=p;
t->father=t->leftChild=t->rightChild=NULL;
//t=NULL;
}

}
else//当左孩子的右孩子不为空时
{
t->father=p;
t->leftChild=p->rightChild;
p->rightChild->father=t;
p->rightChild=t;
if(q==NULL)
{
p->father=NULL;
root=p;
}
else
{
p->father=q;
if(q->leftChild==t)
q->leftChild=p;
else
q->rightChild=p;
}
erase(key);
}
}
else//找出左右孩子中优先级较小的那个
{treapNode<T> *p=t->rightChild;//记录下当前节点的右孩子
if(t->rightChild->leftChild==NULL)//当右孩子的左孩子为空时
{
if(q==NULL)//如果待删节点为根节点
{
p->leftChild=t->leftChild;
p->father=NULL;
t->leftChild->father=p;
t->leftChild=t->rightChild=NULL;
//t=NULL;
root=p;
}
else//待删节点不为根节点
{
p->leftChild=t->leftChild;
t->leftChild->father=p;
p->father=q;
if(q->leftChild==t)
q->leftChild=p;
else
q->rightChild=p;
t->father=t->leftChild=t->rightChild=NULL;
//t=NULL;
}

}
else//当右孩子的左孩子不为空时
{
t->father=p;
t->rightChild=p->leftChild;
p->leftChild->father=t;
p->leftChild=t;
if(q==NULL)
{
p->father=NULL;
root=p;
}
else
{
p->father=q;
if(q->leftChild==t)
q->leftChild=p;
else
q->rightChild=p;
}
erase(key);
}
}
}
treapSize--;
}
}