|
1 |
| -using System; |
| 1 | +using DataStructures.Common; |
| 2 | +using System; |
2 | 3 | using System.Collections.Generic;
|
3 | 4 |
|
4 |
| -using DataStructures.Common; |
5 |
| - |
6 | 5 | namespace DataStructures.Trees
|
7 | 6 | {
|
8 | 7 | /// <summary>
|
@@ -233,8 +232,8 @@ protected virtual void _adjustTreeAfterInsertion(RedBlackTreeNode<TKey> currentN
|
233 | 232 | // This is the simplest step: Basically recolor, and bubble up to see if more work is needed.
|
234 | 233 | if (_safeCheckIsRed(_safeGetSibling(currentNode.Parent)))
|
235 | 234 | {
|
236 |
| - // If it has a sibling and it is red, then then it has a parent |
237 |
| - currentNode.Parent.Color = RedBlackTreeColors.Red; |
| 235 | + // If it has a sibling and it is black, then then it has a parent |
| 236 | + currentNode.Parent.Color = RedBlackTreeColors.Black; |
238 | 237 |
|
239 | 238 | // Color sibling of parent as black
|
240 | 239 | _safeUpdateColor(_safeGetSibling(currentNode.Parent), RedBlackTreeColors.Black);
|
@@ -455,80 +454,97 @@ protected override bool _remove(BSTNode<TKey> nodeToDelete)
|
455 | 454 | }
|
456 | 455 |
|
457 | 456 | /// <summary>
|
458 |
| - /// The internal remove helper. |
459 |
| - /// Separated from the overriden version to avoid casting the objects from BSTNode to RedBlackTreeNode. |
460 |
| - /// This is called from the overriden _remove(BSTNode nodeToDelete) helper. |
| 457 | + /// The internal remove helper. |
| 458 | + /// Separated from the overriden version to avoid casting the objects from BSTNode to RedBlackTreeNode. |
| 459 | + /// This is called from the overriden _remove(BSTNode nodeToDelete) helper. |
461 | 460 | /// </summary>
|
462 | 461 | protected bool _remove(RedBlackTreeNode<TKey> nodeToDelete)
|
463 | 462 | {
|
464 | 463 | if (nodeToDelete == null)
|
| 464 | + { |
465 | 465 | return false;
|
| 466 | + } |
466 | 467 |
|
467 |
| - // Temporary nodes |
468 |
| - RedBlackTreeNode<TKey> node1, node2; |
| 468 | + // Node X moves to the original nodeToDelete position in the tree. |
| 469 | + RedBlackTreeNode<TKey> x; |
469 | 470 |
|
470 |
| - // If nodeToDelete has either one child or no children at all |
471 |
| - if (!nodeToDelete.HasLeftChild || !nodeToDelete.HasRightChild) |
| 471 | + if (nodeToDelete.HasOnlyRightChild) |
472 | 472 | {
|
473 |
| - node1 = nodeToDelete; |
| 473 | + x = nodeToDelete.RightChild; |
| 474 | + Transplant(nodeToDelete, nodeToDelete.RightChild); |
474 | 475 | }
|
475 |
| - else |
| 476 | + else if (nodeToDelete.HasOnlyLeftChild) |
476 | 477 | {
|
477 |
| - // nodeToDelete has two children |
478 |
| - node1 = (RedBlackTreeNode<TKey>)base._findNextLarger(nodeToDelete); |
479 |
| - } |
480 |
| - |
481 |
| - // Left child case |
482 |
| - if (node1.HasLeftChild) |
483 |
| - { |
484 |
| - node2 = node1.LeftChild; |
| 478 | + x = nodeToDelete.LeftChild; |
| 479 | + Transplant(nodeToDelete, nodeToDelete.LeftChild); |
485 | 480 | }
|
486 | 481 | else
|
487 | 482 | {
|
488 |
| - node2 = node1.RightChild; |
489 |
| - } |
490 |
| - |
491 |
| - // If node2 is not null, copy parent references |
492 |
| - if (node2 != null) |
493 |
| - node2.Parent = node1.Parent; |
| 483 | + // Node Y moves to the original node X position in the tree. |
| 484 | + var y = (RedBlackTreeNode<TKey>)_findMinNode(nodeToDelete.RightChild); |
| 485 | + x = y.RightChild; |
494 | 486 |
|
495 |
| - if (node1.Parent != null) |
496 |
| - { |
497 |
| - if (node1.IsLeftChild) |
| 487 | + if (y.Parent == nodeToDelete) |
498 | 488 | {
|
499 |
| - node1.Parent.LeftChild = node2; |
| 489 | + if (x != null) |
| 490 | + { |
| 491 | + x.Parent = y; |
| 492 | + } |
500 | 493 | }
|
501 | 494 | else
|
502 | 495 | {
|
503 |
| - node1.Parent.RightChild = node2; |
| 496 | + Transplant(y, y.RightChild); |
| 497 | + y.RightChild = nodeToDelete.RightChild; |
| 498 | + y.RightChild.Parent = y; |
504 | 499 | }
|
505 |
| - } |
506 |
| - else |
507 |
| - { |
508 |
| - Root = node2; |
509 |
| - Root.Parent = null; |
510 |
| - } |
511 | 500 |
|
512 |
| - // Swap values |
513 |
| - if (!node1.IsEqualTo(nodeToDelete)) |
514 |
| - { |
515 |
| - nodeToDelete.Value = node1.Value; |
| 501 | + Transplant(nodeToDelete, y); |
| 502 | + y.LeftChild = nodeToDelete.LeftChild; |
| 503 | + y.LeftChild.Parent = y; |
| 504 | + y.Color = nodeToDelete.Color; |
| 505 | + |
| 506 | + if (Root == nodeToDelete) |
| 507 | + { |
| 508 | + Root = y; |
| 509 | + Root.Parent = null; |
| 510 | + } |
516 | 511 | }
|
517 | 512 |
|
518 |
| - // Adjust the Red-Black Tree rules |
519 |
| - if (node1.Color == RedBlackTreeColors.Black && node2 != null) |
| 513 | + if (nodeToDelete.Color == RedBlackTreeColors.Black) |
520 | 514 | {
|
521 |
| - _adjustTreeAfterRemoval(node2); |
522 |
| - Root.Color = RedBlackTreeColors.Black; |
| 515 | + _adjustTreeAfterRemoval(x); |
523 | 516 | }
|
524 | 517 |
|
525 |
| - // Decrement the count |
526 | 518 | base._count--;
|
527 | 519 |
|
528 | 520 | return true;
|
529 | 521 | }
|
530 | 522 |
|
| 523 | + /// <summary> |
| 524 | + /// Insert one subtree in the place of the other in his parent. |
| 525 | + /// </summary> |
| 526 | + /// <param name="replaced">Subtree replaced by <param name="replacement">.</param></param> |
| 527 | + /// <param name="replacement">Subtree replaces <param name="replaced">.</param></param> |
| 528 | + private void Transplant(RedBlackTreeNode<TKey> replaced, RedBlackTreeNode<TKey> replacement) |
| 529 | + { |
| 530 | + if (replaced.Parent == null) |
| 531 | + { |
| 532 | + this.Root = replacement; |
| 533 | + } |
| 534 | + else if (replaced == replaced.Parent.LeftChild) |
| 535 | + { |
| 536 | + replaced.Parent.LeftChild = replacement; |
| 537 | + } |
| 538 | + else |
| 539 | + { |
| 540 | + replaced.Parent.RightChild = replacement; |
| 541 | + } |
531 | 542 |
|
| 543 | + if (replacement != null) |
| 544 | + { |
| 545 | + replacement.Parent = replaced.Parent; |
| 546 | + } |
| 547 | + } |
532 | 548 | /*************************************************************************************************/
|
533 | 549 |
|
534 | 550 |
|
|
0 commit comments