7
7
use Danon \IntervalTree \Interval \IntervalInterface ;
8
8
use Iterator ;
9
9
10
+ /**
11
+ * @template TPoint
12
+ * @template TValue
13
+ */
10
14
final class IntervalTree
11
15
{
12
- /** @var Node*/
16
+ /** @var Node<TPoint, TValue> */
13
17
private $ root ;
14
18
15
- /** @var Node */
19
+ /** @var Node<TPoint, TValue> */
16
20
private $ nilNode ;
17
21
18
22
/**
@@ -45,9 +49,8 @@ public function isEmpty(): bool
45
49
46
50
/**
47
51
* Find pairs which intervals intersect with given interval
48
- *
49
- * @param IntervalInterface $interval
50
- * @return Iterator<Pair>
52
+ * @param IntervalInterface<TPoint> $interval
53
+ * @return Iterator<Pair<TPoint, TValue>>
51
54
*/
52
55
public function findIntersections (IntervalInterface $ interval ): Iterator
53
56
{
@@ -60,7 +63,7 @@ public function findIntersections(IntervalInterface $interval): Iterator
60
63
/**
61
64
* Returns true if interval has at least one intersection in tree
62
65
*
63
- * @param IntervalInterface $interval
66
+ * @param IntervalInterface<TPoint> $interval
64
67
* @return bool
65
68
*/
66
69
public function hasIntersection (IntervalInterface $ interval ): bool
@@ -72,7 +75,7 @@ public function hasIntersection(IntervalInterface $interval): bool
72
75
/**
73
76
* Count intervals that has intersections
74
77
*
75
- * @param IntervalInterface $interval
78
+ * @param IntervalInterface<TPoint> $interval
76
79
* @return int
77
80
*/
78
81
public function countIntersections (IntervalInterface $ interval ): int
@@ -84,8 +87,8 @@ public function countIntersections(IntervalInterface $interval): int
84
87
/**
85
88
* Insert new pair (interval + value) into interval tree
86
89
*
87
- * @param IntervalInterface $interval
88
- * @param mixed $value
90
+ * @param IntervalInterface<TPoint> $interval
91
+ * @param TValue $value
89
92
*/
90
93
public function insert (IntervalInterface $ interval , $ value = null ): void
91
94
{
@@ -103,8 +106,8 @@ public function insert(IntervalInterface $interval, $value = null): void
103
106
/**
104
107
* Returns true if interval and value exist in the tree
105
108
*
106
- * @param IntervalInterface $interval
107
- * @param mixed $value
109
+ * @param IntervalInterface<TPoint> $interval
110
+ * @param TValue $value
108
111
* @return bool
109
112
*/
110
113
public function exist (IntervalInterface $ interval , $ value ): bool
@@ -116,8 +119,8 @@ public function exist(IntervalInterface $interval, $value): bool
116
119
/**
117
120
* Remove node from tree by interval and value
118
121
*
119
- * @param IntervalInterface $interval
120
- * @param mixed $value
122
+ * @param IntervalInterface<TPoint> $interval
123
+ * @param TValue $value
121
124
* @return bool
122
125
*/
123
126
public function remove (IntervalInterface $ interval , $ value ): bool
@@ -131,6 +134,10 @@ public function remove(IntervalInterface $interval, $value): bool
131
134
return false ;
132
135
}
133
136
137
+ /**
138
+ * @param Node<TPoint, TValue> $node
139
+ * @return void
140
+ */
134
141
private function recalculateMax (Node $ node ): void
135
142
{
136
143
$ nodeCurrent = $ node ;
@@ -140,6 +147,10 @@ private function recalculateMax(Node $node): void
140
147
}
141
148
}
142
149
150
+ /**
151
+ * @param Node<TPoint, TValue> $insertNode
152
+ * @return void
153
+ */
143
154
private function treeInsert (Node $ insertNode ): void
144
155
{
145
156
$ currentNode = $ this ->root ;
@@ -170,11 +181,7 @@ private function treeInsert(Node $insertNode): void
170
181
}
171
182
172
183
/**
173
- * After insertion insert_node may have red-colored parent
174
- * And this is a single possible violation
175
- * Go upwards to the root and re-color until violation will be resolved
176
- *
177
- * @param Node $insertNode
184
+ * @param Node<TPoint, TValue> $insertNode
178
185
*/
179
186
private function insertFixup (Node $ insertNode ): void
180
187
{
@@ -218,6 +225,10 @@ private function insertFixup(Node $insertNode): void
218
225
$ this ->root ->setColor (NodeColor::black ());
219
226
}
220
227
228
+ /**
229
+ * @param Node<TPoint, TValue> $deleteNode
230
+ * @return void
231
+ */
221
232
private function treeDelete (Node $ deleteNode ): void
222
233
{
223
234
if ($ deleteNode ->getLeft () === $ this ->nilNode || $ deleteNode ->getRight () === $ this ->nilNode ) {
@@ -226,7 +237,6 @@ private function treeDelete(Node $deleteNode): void
226
237
$ cutNode = $ this ->treeSuccessor ($ deleteNode );
227
238
}
228
239
229
- // fix_node if single child of cut_node
230
240
if ($ cutNode ->getLeft () !== $ this ->nilNode ) {
231
241
$ fixNode = $ cutNode ->getLeft ();
232
242
} else {
@@ -243,24 +253,26 @@ private function treeDelete(Node $deleteNode): void
243
253
} else {
244
254
$ cutNode ->getParent ()->setRight ($ fixNode );
245
255
}
246
- $ cutNode ->getParent ()->updateMax (); // update max property of the parent
256
+ $ cutNode ->getParent ()->updateMax ();
247
257
}
248
258
249
- $ this ->recalculateMax ($ fixNode ); // update max property upward from fix_node to root
259
+ $ this ->recalculateMax ($ fixNode );
250
260
251
- // deleteNode becomes cutNode, it means that we cannot hold reference
252
- // to node in outer structure and we will have to delete by key, additional search need
253
261
if ($ cutNode !== $ deleteNode ) {
254
262
$ deleteNode ->copyPairFrom ($ cutNode );
255
- $ deleteNode ->updateMax (); // update max property of the cut node at the new place
256
- $ this ->recalculateMax ($ deleteNode ); // update max property upward from deleteNode to root
263
+ $ deleteNode ->updateMax ();
264
+ $ this ->recalculateMax ($ deleteNode );
257
265
}
258
266
259
267
if ($ cutNode ->getColor ()->isBlack ()) {
260
268
$ this ->deleteFixup ($ fixNode );
261
269
}
262
270
}
263
271
272
+ /**
273
+ * @param Node<TPoint, TValue> $fixNode
274
+ * @return void
275
+ */
264
276
private function deleteFixup (Node $ fixNode ): void
265
277
{
266
278
$ currentNode = $ fixNode ;
@@ -286,7 +298,6 @@ private function deleteFixup(Node $fixNode): void
286
298
$ brotherNode ->setColor (NodeColor::red ());
287
299
$ brotherNode ->getLeft ()->setColor (NodeColor::black ());
288
300
$ this ->rotateRight ($ brotherNode );
289
- $ brotherNode = $ currentNode ->getParent ()->getRight ();
290
301
}
291
302
$ brotherNode ->setColor ($ currentNode ->getParent ()->getColor ());
292
303
$ currentNode ->getParent ()->setColor (NodeColor::black ());
@@ -310,7 +321,6 @@ private function deleteFixup(Node $fixNode): void
310
321
$ brotherNode ->setColor (NodeColor::red ());
311
322
$ brotherNode ->getRight ()->setColor (NodeColor::black ());
312
323
$ this ->rotateLeft ($ brotherNode );
313
- $ brotherNode = $ currentNode ->getParent ()->getLeft ();
314
324
}
315
325
$ brotherNode ->setColor ($ currentNode ->getParent ()->getColor ());
316
326
$ currentNode ->getParent ()->setColor (NodeColor::black ());
@@ -324,27 +334,32 @@ private function deleteFixup(Node $fixNode): void
324
334
$ currentNode ->setColor (NodeColor::black ());
325
335
}
326
336
327
- private function treeSearch (Node $ node , Node $ searchNode ): ?Node
337
+ /**
338
+ * @param Node<TPoint, TValue> $startingNode
339
+ * @param Node<TPoint, TValue> $node
340
+ * @return Node<TPoint, TValue>|null
341
+ */
342
+ private function treeSearch (Node $ startingNode , Node $ node ): ?Node
328
343
{
329
- if ($ node === $ this ->nilNode ) {
344
+ if ($ startingNode === $ this ->nilNode ) {
330
345
return null ;
331
346
}
332
347
333
- if ($ searchNode ->equalTo ($ node )) {
334
- return $ node ;
335
- }
336
-
337
- if ( $ searchNode -> lessThan ( $ node )) {
338
- return $ this ->treeSearch ($ node -> getLeft (), $ searchNode );
348
+ if ($ node ->equalTo ($ startingNode )) {
349
+ $ searchedNode = $ startingNode ;
350
+ } elseif ( $ node -> lessThan ( $ startingNode )) {
351
+ $ searchedNode = $ this -> treeSearch ( $ startingNode -> getLeft (), $ node );
352
+ } else {
353
+ $ searchedNode = $ this ->treeSearch ($ startingNode -> getRight (), $ node );
339
354
}
340
355
341
- return $ this -> treeSearch ( $ node -> getRight (), $ searchNode ) ;
356
+ return $ searchedNode ;
342
357
}
343
358
344
359
/**
345
- * @param Node $searchNode
346
- * @param Node|null $fromNode
347
- * @return Iterator<Node>
360
+ * @param Node<TPoint, TValue> $searchNode
361
+ * @param Node<TPoint, TValue> |null $fromNode
362
+ * @return Iterator<Node<TPoint, TValue> >
348
363
*/
349
364
private function treeSearchInterval (Node $ searchNode , Node $ fromNode = null ): Iterator
350
365
{
@@ -360,6 +375,10 @@ private function treeSearchInterval(Node $searchNode, Node $fromNode = null): It
360
375
}
361
376
}
362
377
378
+ /**
379
+ * @param Node<TPoint, TValue> $node
380
+ * @return Node<TPoint, TValue>
381
+ */
363
382
private function localMinimum (Node $ node ): Node
364
383
{
365
384
$ nodeMin = $ node ;
@@ -369,6 +388,10 @@ private function localMinimum(Node $node): Node
369
388
return $ nodeMin ;
370
389
}
371
390
391
+ /**
392
+ * @param Node<TPoint, TValue> $node
393
+ * @return Node<TPoint, TValue>|null
394
+ */
372
395
private function treeSuccessor (Node $ node ): ?Node
373
396
{
374
397
if ($ node ->getRight () !== $ this ->nilNode ) {
@@ -385,25 +408,29 @@ private function treeSuccessor(Node $node): ?Node
385
408
return $ nodeSuccessor ;
386
409
}
387
410
411
+ /**
412
+ * @param Node<TPoint, TValue> $x
413
+ * @return void
414
+ */
388
415
private function rotateLeft (Node $ x ): void
389
416
{
390
417
$ y = $ x ->getRight ();
391
- $ x ->setRight ($ y ->getLeft ()); // b goes to x.right
418
+ $ x ->setRight ($ y ->getLeft ());
392
419
393
420
if ($ y ->getLeft () !== $ this ->nilNode ) {
394
- $ y ->getLeft ()->setParent ($ x ); // x becomes parent of b
421
+ $ y ->getLeft ()->setParent ($ x );
395
422
}
396
- $ y ->setParent ($ x ->getParent ()); // move parent
423
+ $ y ->setParent ($ x ->getParent ());
397
424
398
425
if ($ x ->getParent () === null ) {
399
- $ this ->root = $ y ; // y becomes root
426
+ $ this ->root = $ y ;
400
427
} elseif ($ x === $ x ->getParent ()->getLeft ()) {
401
428
$ x ->getParent ()->setLeft ($ y );
402
429
} else {
403
430
$ x ->getParent ()->setRight ($ y );
404
431
}
405
- $ y ->setLeft ($ x ); // x becomes left child of y
406
- $ x ->setParent ($ y ); // and y becomes parent of x
432
+ $ y ->setLeft ($ x );
433
+ $ x ->setParent ($ y );
407
434
408
435
if ($ x !== $ this ->nilNode ) {
409
436
$ x ->updateMax ();
@@ -415,26 +442,30 @@ private function rotateLeft(Node $x): void
415
442
}
416
443
}
417
444
445
+ /**
446
+ * @param Node<TPoint, TValue> $y
447
+ * @return void
448
+ */
418
449
private function rotateRight (Node $ y ): void
419
450
{
420
451
$ x = $ y ->getLeft ();
421
452
422
- $ y ->setLeft ($ x ->getRight ()); // b goes to y.left
453
+ $ y ->setLeft ($ x ->getRight ());
423
454
424
455
if ($ x ->getRight () !== $ this ->nilNode ) {
425
- $ x ->getRight ()->setParent ($ y ); // y becomes parent of b
456
+ $ x ->getRight ()->setParent ($ y );
426
457
}
427
- $ x ->setParent ($ y ->getParent ()); // move parent
458
+ $ x ->setParent ($ y ->getParent ());
428
459
429
- if ($ y ->getParent () === null ) { // x becomes root
460
+ if ($ y ->getParent () === null ) {
430
461
$ this ->root = $ x ;
431
462
} elseif ($ y === $ y ->getParent ()->getLeft ()) {
432
463
$ y ->getParent ()->setLeft ($ x );
433
464
} else {
434
465
$ y ->getParent ()->setRight ($ x );
435
466
}
436
- $ x ->setRight ($ y ); // y becomes right child of x
437
- $ y ->setParent ($ x ); // and x becomes parent of y
467
+ $ x ->setRight ($ y );
468
+ $ y ->setParent ($ x );
438
469
439
470
if ($ y !== $ this ->nilNode ) {
440
471
$ y ->updateMax ();
@@ -447,9 +478,9 @@ private function rotateRight(Node $y): void
447
478
}
448
479
449
480
/**
450
- * @return Iterator<Node>
481
+ * @return Iterator<Node<TPoint, TValue> >
451
482
*/
452
- public function treeWalk (): Iterator
483
+ private function treeWalk (): Iterator
453
484
{
454
485
if ($ this ->root !== null ) {
455
486
$ stack = [$ this ->root ];
0 commit comments