IntrusiveRedBlackTree.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. using System;
  2. namespace Ryujinx.Common.Collections
  3. {
  4. /// <summary>
  5. /// Tree that provides the ability for O(logN) lookups for keys that exist in the tree, and O(logN) lookups for keys immediately greater than or less than a specified key.
  6. /// </summary>
  7. /// <typeparam name="T">Derived node type</typeparam>
  8. public class IntrusiveRedBlackTree<T> : IntrusiveRedBlackTreeImpl<T> where T : IntrusiveRedBlackTreeNode<T>, IComparable<T>
  9. {
  10. #region Public Methods
  11. /// <summary>
  12. /// Adds a new node into the tree.
  13. /// </summary>
  14. /// <param name="node">Node to be added</param>
  15. /// <exception cref="ArgumentNullException"><paramref name="node"/> is null</exception>
  16. public void Add(T node)
  17. {
  18. ArgumentNullException.ThrowIfNull(node);
  19. Insert(node);
  20. }
  21. /// <summary>
  22. /// Removes a node from the tree.
  23. /// </summary>
  24. /// <param name="node">Note to be removed</param>
  25. /// <exception cref="ArgumentNullException"><paramref name="node"/> is null</exception>
  26. public void Remove(T node)
  27. {
  28. ArgumentNullException.ThrowIfNull(node);
  29. if (Delete(node) != null)
  30. {
  31. Count--;
  32. }
  33. }
  34. /// <summary>
  35. /// Retrieve the node that is considered equal to the specified node by the comparator.
  36. /// </summary>
  37. /// <param name="searchNode">Node to compare with</param>
  38. /// <returns>Node that is equal to <paramref name="searchNode"/></returns>
  39. /// <exception cref="ArgumentNullException"><paramref name="searchNode"/> is null</exception>
  40. public T GetNode(T searchNode)
  41. {
  42. ArgumentNullException.ThrowIfNull(searchNode);
  43. T node = Root;
  44. while (node != null)
  45. {
  46. int cmp = searchNode.CompareTo(node);
  47. if (cmp < 0)
  48. {
  49. node = node.Left;
  50. }
  51. else if (cmp > 0)
  52. {
  53. node = node.Right;
  54. }
  55. else
  56. {
  57. return node;
  58. }
  59. }
  60. return null;
  61. }
  62. #endregion
  63. #region Private Methods (BST)
  64. /// <summary>
  65. /// Inserts a new node into the tree.
  66. /// </summary>
  67. /// <param name="node">Node to be inserted</param>
  68. private void Insert(T node)
  69. {
  70. T newNode = BSTInsert(node);
  71. RestoreBalanceAfterInsertion(newNode);
  72. }
  73. /// <summary>
  74. /// Insertion Mechanism for a Binary Search Tree (BST).
  75. /// <br></br>
  76. /// Iterates the tree starting from the root and inserts a new node
  77. /// where all children in the left subtree are less than <paramref name="newNode"/>,
  78. /// and all children in the right subtree are greater than <paramref name="newNode"/>.
  79. /// </summary>
  80. /// <param name="newNode">Node to be inserted</param>
  81. /// <returns>The inserted Node</returns>
  82. private T BSTInsert(T newNode)
  83. {
  84. T parent = null;
  85. T node = Root;
  86. while (node != null)
  87. {
  88. parent = node;
  89. int cmp = newNode.CompareTo(node);
  90. if (cmp < 0)
  91. {
  92. node = node.Left;
  93. }
  94. else if (cmp > 0)
  95. {
  96. node = node.Right;
  97. }
  98. else
  99. {
  100. return node;
  101. }
  102. }
  103. newNode.Parent = parent;
  104. if (parent == null)
  105. {
  106. Root = newNode;
  107. }
  108. else if (newNode.CompareTo(parent) < 0)
  109. {
  110. parent.Left = newNode;
  111. }
  112. else
  113. {
  114. parent.Right = newNode;
  115. }
  116. Count++;
  117. return newNode;
  118. }
  119. /// <summary>
  120. /// Removes <paramref name="nodeToDelete"/> from the tree, if it exists.
  121. /// </summary>
  122. /// <param name="nodeToDelete">Node to be removed</param>
  123. /// <returns>The deleted Node</returns>
  124. private T Delete(T nodeToDelete)
  125. {
  126. if (nodeToDelete == null)
  127. {
  128. return null;
  129. }
  130. T old = nodeToDelete;
  131. T child;
  132. T parent;
  133. bool color;
  134. if (LeftOf(nodeToDelete) == null)
  135. {
  136. child = RightOf(nodeToDelete);
  137. }
  138. else if (RightOf(nodeToDelete) == null)
  139. {
  140. child = LeftOf(nodeToDelete);
  141. }
  142. else
  143. {
  144. T element = Minimum(RightOf(nodeToDelete));
  145. child = RightOf(element);
  146. parent = ParentOf(element);
  147. color = ColorOf(element);
  148. if (child != null)
  149. {
  150. child.Parent = parent;
  151. }
  152. if (parent == null)
  153. {
  154. Root = child;
  155. }
  156. else if (element == LeftOf(parent))
  157. {
  158. parent.Left = child;
  159. }
  160. else
  161. {
  162. parent.Right = child;
  163. }
  164. if (ParentOf(element) == old)
  165. {
  166. parent = element;
  167. }
  168. element.Color = old.Color;
  169. element.Left = old.Left;
  170. element.Right = old.Right;
  171. element.Parent = old.Parent;
  172. if (ParentOf(old) == null)
  173. {
  174. Root = element;
  175. }
  176. else if (old == LeftOf(ParentOf(old)))
  177. {
  178. ParentOf(old).Left = element;
  179. }
  180. else
  181. {
  182. ParentOf(old).Right = element;
  183. }
  184. LeftOf(old).Parent = element;
  185. if (RightOf(old) != null)
  186. {
  187. RightOf(old).Parent = element;
  188. }
  189. if (child != null && color == Black)
  190. {
  191. RestoreBalanceAfterRemoval(child);
  192. }
  193. return old;
  194. }
  195. parent = ParentOf(nodeToDelete);
  196. color = ColorOf(nodeToDelete);
  197. if (child != null)
  198. {
  199. child.Parent = parent;
  200. }
  201. if (parent == null)
  202. {
  203. Root = child;
  204. }
  205. else if (nodeToDelete == LeftOf(parent))
  206. {
  207. parent.Left = child;
  208. }
  209. else
  210. {
  211. parent.Right = child;
  212. }
  213. if (child != null && color == Black)
  214. {
  215. RestoreBalanceAfterRemoval(child);
  216. }
  217. return old;
  218. }
  219. #endregion
  220. }
  221. public static class IntrusiveRedBlackTreeExtensions
  222. {
  223. /// <summary>
  224. /// Retrieve the node that is considered equal to the key by the comparator.
  225. /// </summary>
  226. /// <param name="tree">Tree to search at</param>
  227. /// <param name="key">Key of the node to be found</param>
  228. /// <returns>Node that is equal to <paramref name="key"/></returns>
  229. public static N GetNodeByKey<N, K>(this IntrusiveRedBlackTree<N> tree, K key)
  230. where N : IntrusiveRedBlackTreeNode<N>, IComparable<N>, IComparable<K>
  231. where K : struct
  232. {
  233. N node = tree.RootNode;
  234. while (node != null)
  235. {
  236. int cmp = node.CompareTo(key);
  237. if (cmp < 0)
  238. {
  239. node = node.Right;
  240. }
  241. else if (cmp > 0)
  242. {
  243. node = node.Left;
  244. }
  245. else
  246. {
  247. return node;
  248. }
  249. }
  250. return null;
  251. }
  252. }
  253. }