• 红黑树-自平衡二叉搜索树


    一、简介

    红黑树(Red-Black Tree)是一种自平衡的二叉搜索树,它的节点可以是红色或黑色。这个颜色的设计是为了满足红黑树的五个关键性质,确保树保持平衡和高效地支持插入、删除和搜索操作。

    以下是红黑树的五个关键性质:

    1. 每个节点要么是红色,要么是黑色。
    2. 根节点是黑色的。
    3. 每个叶子节点(NIL节点,通常表示为黑色)是黑色的。
    4. 如果一个节点是红色的,那么它的两个子节点都是黑色的。
    5. 对于每个节点,从该节点到其后代任意叶子节点,经过的黑色节点的数量都相同。

    这些性质确保了红黑树的平衡性,使得树的高度保持在可控范围内,从而保证了基本的搜索、插入和删除操作的时间复杂度为 O(log n),其中 n 是树中节点的数量。

    红色节点和黑色节点的交替排列和上述性质的约束是为了保持树的平衡性。通过确保在树中的任何路径上都有相同数量的黑色节点,红黑树可以防止出现极端不平衡的情况,从而保证了树的高度保持在可控的范围内。红色节点的存在有助于确保在插入和删除节点时树能够重新平衡。

    总之,红黑树中的红色节点和黑色节点是为了满足平衡性和其他性质而设计的,它们共同确保了红黑树的高效性和可预测性。

    二、红黑树的操作

    首先我们来看一个红黑树(红节点H,M也有叶子节点NIL没有画出了):

    由此可见,红黑树并不是一个完美平衡二叉查找树,根结点P的左子树显然比右子树高,但左子树和右子树的黑结点的层数是相等的,也即任意一个结点到到每个叶子结点的路径都包含数量相同的黑结点(性质5)。所以我们叫红黑树这种平衡为黑色完美平衡
    由于红节点总是插入在黑节点中,所以左子树与右子树最大的差距也不会超过2倍,这就保证了树的平衡性。
    例如 :------,长度分别为5跟3,即5/3约等于1.6倍,显然没有超过2倍。

    前面讲到红黑树能自平衡,它靠的是什么操作?三种操作:左旋、右旋和变色。

    • 左旋:以某个结点作为支点(旋转结点),其右子结点变为旋转结点的父结点,右子结点的左子结点变为旋转结点的右子结点,左子结点保持不变。如图3。
    • 右旋:以某个结点作为支点(旋转结点),其左子结点变为旋转结点的父结点,左子结点的右子结点变为旋转结点的左子结点,右子结点保持不变。如图4。
    • 变色:结点的颜色由红变黑或由黑变红。

    图三
    图3
    图4

    三、实现

    1. using System;
    2. public enum NodeColor
    3. {
    4. Red,
    5. Black
    6. }
    7. public class Node
    8. {
    9. public int Data { get; set; }
    10. public Node Parent { get; set; }
    11. public Node Left { get; set; }
    12. public Node Right { get; set; }
    13. public NodeColor Color { get; set; }
    14. }
    15. public class RedBlackTree
    16. {
    17. private Node root;
    18. // 插入节点
    19. public void Insert(int data)
    20. {
    21. var node = new Node { Data = data, Color = NodeColor.Red };
    22. if (root == null)
    23. {
    24. root = node;
    25. root.Color = NodeColor.Black;
    26. }
    27. else
    28. {
    29. InsertNode(root, node);
    30. FixTree(node);
    31. }
    32. }
    33. // 辅助方法:插入节点
    34. private void InsertNode(Node root, Node newNode)
    35. {
    36. if (newNode.Data < root.Data)
    37. {
    38. if (root.Left == null)
    39. {
    40. root.Left = newNode;
    41. newNode.Parent = root;
    42. }
    43. else
    44. InsertNode(root.Left, newNode);
    45. }
    46. else
    47. {
    48. if (root.Right == null)
    49. {
    50. root.Right = newNode;
    51. newNode.Parent = root;
    52. }
    53. else
    54. InsertNode(root.Right, newNode);
    55. }
    56. }
    57. // 辅助方法:修复红黑树性质
    58. private void FixTree(Node node)
    59. {
    60. while (node != root && node.Parent.Color == NodeColor.Red)
    61. {
    62. if (node.Parent == node.Parent.Parent.Left)
    63. {
    64. var uncle = node.Parent.Parent.Right;
    65. if (uncle != null && uncle.Color == NodeColor.Red)
    66. {
    67. node.Parent.Color = NodeColor.Black;
    68. uncle.Color = NodeColor.Black;
    69. node.Parent.Parent.Color = NodeColor.Red;
    70. node = node.Parent.Parent;
    71. }
    72. else
    73. {
    74. if (node == node.Parent.Right)
    75. {
    76. node = node.Parent;
    77. RotateLeft(node);
    78. }
    79. node.Parent.Color = NodeColor.Black;
    80. node.Parent.Parent.Color = NodeColor.Red;
    81. RotateRight(node.Parent.Parent);
    82. }
    83. }
    84. else
    85. {
    86. var uncle = node.Parent.Parent.Left;
    87. if (uncle != null && uncle.Color == NodeColor.Red)
    88. {
    89. node.Parent.Color = NodeColor.Black;
    90. uncle.Color = NodeColor.Black;
    91. node.Parent.Parent.Color = NodeColor.Red;
    92. node = node.Parent.Parent;
    93. }
    94. else
    95. {
    96. if (node == node.Parent.Left)
    97. {
    98. node = node.Parent;
    99. RotateRight(node);
    100. }
    101. node.Parent.Color = NodeColor.Black;
    102. node.Parent.Parent.Color = NodeColor.Red;
    103. RotateLeft(node.Parent.Parent);
    104. }
    105. }
    106. }
    107. root.Color = NodeColor.Black;
    108. }
    109. // 左旋
    110. private void RotateLeft(Node node)
    111. {
    112. var temp = node.Right;
    113. node.Right = temp.Left;
    114. if (temp.Left != null)
    115. temp.Left.Parent = node;
    116. if (temp != null)
    117. temp.Parent = node.Parent;
    118. if (node.Parent == null)
    119. root = temp;
    120. else if (node == node.Parent.Left)
    121. node.Parent.Left = temp;
    122. else
    123. node.Parent.Right = temp;
    124. temp.Left = node;
    125. if (node != null)
    126. node.Parent = temp;
    127. }
    128. // 右旋
    129. private void RotateRight(Node node)
    130. {
    131. var temp = node.Left;
    132. node.Left = temp.Right;
    133. if (temp.Right != null)
    134. temp.Right.Parent = node;
    135. if (temp != null)
    136. temp.Parent = node.Parent;
    137. if (node.Parent == null)
    138. root = temp;
    139. else if (node == node.Parent.Right)
    140. node.Parent.Right = temp;
    141. else
    142. node.Parent.Left = temp;
    143. temp.Right = node;
    144. if (node != null)
    145. node.Parent = temp;
    146. }
    147. // 中序遍历
    148. public void InOrderTraversal(Node node)
    149. {
    150. if (node != null)
    151. {
    152. InOrderTraversal(node.Left);
    153. Console.WriteLine(node.Data + " " + node.Color);
    154. InOrderTraversal(node.Right);
    155. }
    156. }
    157. }


    参考博客:30张图带你彻底理解红黑树

  • 相关阅读:
    【Android】Fragment使用
    Java刷题day29
    Unity实现角色受到攻击后屏幕抖动的效果
    Linux下如何打包库供别人使用
    【自动驾驶】路径规划—— Dubins 曲线公式总结及python代码实现(基于几何的方法)
    S级猫主食冻干测评出来了:希喂、K9、朗诺实测分享
    C++ 【new,delete内存管理】
    测试面试官会做些什么?
    【6】Docker中部署Nginx
    BLE Mesh蓝牙mesh网多跳大数据量高带宽传输数据方法
  • 原文地址:https://blog.csdn.net/sindyra/article/details/133348392