-
Notifications
You must be signed in to change notification settings - Fork 0
/
treap.pas
331 lines (298 loc) · 7.73 KB
/
treap.pas
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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
{$mode objfpc}{$H+}{$J-}
{$ASSERTIONS ON}
{$warnings on}
{$hints on}
{$R+}{$Q+}
unit treap;
interface
uses Classes, SysUtils, rheap;
type
generic TTreapNode<T> = class(TRandomHeapNode)
private
// Key
FKey: T;
public
(* Tree node constructor. *)
constructor Create(const k: T);
(* Tree node destructor. *)
destructor Destroy; override;
(* Divides tree into two trees. Where @code(Max(l) <= k). *)
class procedure DivideRight(node: TTreapNode; k: T; var l, r: TTreapNode);
(* Divides tree into two trees. Where @code(Max(l) < k). *)
class procedure DivideLeft(node: TTreapNode; k: T; var l, r: TTreapNode);
(* Insert key @code(k) in tree rooted at @code(node). *)
class procedure Insert(var node: TTreapNode; const k: T); inline;
(* Check if tree rooted at @code(root) node contains key @code(k). *)
class function Contains(node: TTreapNode; const k: T): boolean; inline;
(* Number of keys less than @code(k) *)
class function BisectLeft(node: TTreapNode; const k: T): SizeUInt;
(* Number of keys less or equal @code(k) *)
class function BisectRight(node: TTreapNode; const k: T): SizeUInt;
class function GetPosition(node: TTreapNode; const k: T): SizeUInt;
(* @raises(EArgumentException) *)
class function GetAt(node: TTreapNode; pos: SizeUInt): T;
class function Min(node: TTreapNode): T;
class function Max(node: TTreapNode): T;
(* Removes key from the tree.
@returns(@true if successful, @false otherwise) *)
class function Remove(var node: TTreapNode; const k: T): boolean;
(* Removes key from the given position.
@returns(key) *)
class function RemoveAt(var node: TTreapNode; const pos: SizeUInt): T;
(* Destroy tree. *)
class procedure DestroyTreap(var node: TTreapNode);
class function CheckStucture(node: TTreapNode): boolean;
end;
implementation
//
// TTreapNode Class methods
//
constructor TTreapNode.Create(const k: T);
begin
inherited Create;
FKey := k;
end;
destructor TTreapNode.Destroy;
begin
inherited;
end;
class procedure TTreapNode.DivideRight(node: TTreapNode; k: T; var l, r: TTreapNode);
begin
if node = nil then
begin
l := nil;
r := nil;
Exit;
end;
if k < node.FKey then
begin
DivideRight(TTreapNode(node.FLeft), k, l, TTreapNode(node.FLeft));
r := node;
end
else
begin
DivideRight(TTreapNode(node.FRight), k, TTreapNode(node.FRight), r);
l := node;
end;
UpdateSize(node);
end;
class procedure TTreapNode.DivideLeft(node: TTreapNode; k: T; var l, r: TTreapNode);
begin
if node = nil then
begin
l := nil;
r := nil;
Exit;
end;
if k > node.FKey then
begin
DivideLeft(TTreapNode(node.FRight), k, TTreapNode(node.FRight), r);
l := node;
end
else
begin
DivideLeft(TTreapNode(node.FLeft), k, l, TTreapNode(node.FLeft));
r := node;
end;
UpdateSize(node);
end;
class procedure TTreapNode.Insert(var node: TTreapNode; const k: T); inline;
var
l: TTreapNode = nil;
r: TTreapNode = nil;
begin
DivideRight(node, k, l, r);
node := Meld(TTreapNode.Create(k), r) as TTreapNode;
node := Meld(l, node) as TTreapNode;
end;
// PASSED
class function TTreapNode.Contains(node: TTreapNode; const k: T): boolean; inline;
begin
while node <> nil do
begin
if k = node.FKey then
Exit(True);
if k > node.FKey then
node := TTreapNode(node.FRight)
else
node := TTreapNode(node.FLeft);
end;
Exit(False);
end;
class function TTreapNode.BisectLeft(node: TTreapNode; const k: T): SizeUInt;
var
pos: SizeUInt = 0;
begin
while node <> nil do
begin
if k > node.FKey then
begin
pos := pos + GetSize(node.FLeft) + 1;
node := TTreapNode(node.FRight);
end
else
node := TTreapNode(node.FLeft);
end;
Exit(pos);
end;
class function TTreapNode.BisectRight(node: TTreapNode; const k: T): SizeUInt;
var
pos: SizeUInt = 0;
begin
while node <> nil do
begin
if k < node.FKey then
node := TTreapNode(node.FLeft)
else
begin
pos := pos + GetSize(node.FLeft) + 1;
node := TTreapNode(node.FRight);
end;
end;
Exit(pos);
end;
// PASSED
class function TTreapNode.GetPosition(node: TTreapNode; const k: T): SizeUInt;
var
pos: SizeUInt = 0;
begin
while node <> nil do
begin
if k = node.FKey then
Exit(pos + GetSize(node.FLeft));
if k > node.FKey then
begin
pos := pos + GetSize(node.FLeft) + 1;
node := TTreapNode(node.FRight);
end
else
node := TTreapNode(node.FLeft);
end;
raise Exception.Create('No such key');
end;
// PASSED
class function TTreapNode.GetAt(node: TTreapNode; pos: SizeUInt): T;
var
lsize: SizeUInt = 0;
begin
if (node = nil) or (pos > GetSize(node) - 1) then
raise EArgumentException.Create('Set is empty or position is out of range.');
while node <> nil do
begin
lsize := GetSize(node.FLeft);
if pos = lsize then
Exit(node.FKey);
if pos > lsize then
begin
node := TTreapNode(node.FRight);
pos := pos - lsize - 1;
end
else
node := TTreapNode(node.FLeft);
end;
raise Exception.Create('Unreachable point.');
end;
// Min, Max
class function TTreapNode.Min(node: TTreapNode): T;
begin
if node = nil then
raise EArgumentException.Create('Set is empty.');
while node.FLeft <> nil do
node := TTreapNode(node.FLeft);
Exit(node.FKey);
end;
class function TTreapNode.Max(node: TTreapNode): T;
begin
if node = nil then
raise EArgumentException.Create('Set is empty.');
while node.FRight <> nil do
node := TTreapNode(node.FRight);
Exit(node.FKey);
end;
// Min, Max
class function TTreapNode.Remove(var node: TTreapNode; const k: T): boolean;
var
n: TTreapNode;
begin
Result := False;
if node <> nil then
begin
if k = node.FKey then
begin
n := node;
node := TTreapNode(Meld(node.FLeft, node.FRight));
FreeAndNil(n);
Exit(True);
end;
if k > node.FKey then
begin
Result := Remove(TTreapNode(node.FRight), k)
end
else
begin
Result := Remove(TTreapNode(node.FLeft), k);
end;
if Result then
UpdateSize(node);
end;
end;
// RWRT
class function TTreapNode.RemoveAt(var node: TTreapNode; const pos: SizeUInt): T;
var
n: TTreapNode;
begin
if (node = nil) or (pos > GetSize(node) - 1) then
raise EArgumentException.Create('Set is empty or position is out of range.');
if pos = GetSize(node.FLeft) then
begin
Result := node.FKey;
n := node;
node := TTreapNode(Meld(node.FLeft, node.FRight));
FreeAndNil(n);
Exit;
end;
if pos > GetSize(node.FLeft) then
begin
Result := RemoveAt(TTreapNode(node.FRight), pos - GetSize(node.FLeft) - 1)
end
else
begin
Result := RemoveAt(TTreapNode(node.FLeft), pos);
end;
UpdateSize(node);
end;
class procedure TTreapNode.DestroyTreap(var node: TTreapNode);
begin
if node <> nil then
begin
DestroyTreap(TTreapNode(node.FLeft));
DestroyTreap(TTreapNode(node.FRight));
FreeAndNil(node);
end;
end;
class function TTreapNode.CheckStucture(node: TTreapNode): boolean;
begin
Result := True;
if node = nil then
Exit(Result);
with node do
begin
Result := Result and CheckStucture(TTreapNode(node.FLeft));
Result := Result and CheckStucture(TTreapNode(node.FRight));
Result := Result and (GetSize(node) = GetSize(node.FLeft) +
GetSize(node.FRight) + 1);
if node.FLeft <> nil then
begin
Result := Result and (node.FPriority >= node.FLeft.FPriority);
Result := Result and ((node.FKey >= TTreapNode(node.FLeft).FKey));
end;
if node.FRight <> nil then
begin
Result := Result and (node.FPriority >= node.FRight.FPriority);
Result := Result and (node.FKey < TTreapNode(node.FRight).FKey);
end;
end;
end;
initialization
Randomize;
end.