IntrusiveRedBlackTree.cs 8.3 KB

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