IntervalTree.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  1. using System;
  2. using System.Collections.Generic;
  3. namespace ARMeilleure.Translation
  4. {
  5. /// <summary>
  6. /// An Augmented Interval Tree based off of the "TreeDictionary"'s Red-Black Tree. Allows fast overlap checking of ranges.
  7. /// </summary>
  8. /// <typeparam name="K">Key</typeparam>
  9. /// <typeparam name="V">Value</typeparam>
  10. class IntervalTree<K, V> where K : IComparable<K>
  11. {
  12. private const int ArrayGrowthSize = 32;
  13. private const bool Black = true;
  14. private const bool Red = false;
  15. private IntervalTreeNode<K, V> _root = null;
  16. private int _count = 0;
  17. public int Count => _count;
  18. #region Public Methods
  19. /// <summary>
  20. /// Gets the values of the interval whose key is <paramref name="key"/>.
  21. /// </summary>
  22. /// <param name="key">Key of the node value to get</param>
  23. /// <param name="value">Value with the given <paramref name="key"/></param>
  24. /// <returns>True if the key is on the dictionary, false otherwise</returns>
  25. public bool TryGet(K key, out V value)
  26. {
  27. IntervalTreeNode<K, V> node = GetNode(key);
  28. if (node == null)
  29. {
  30. value = default;
  31. return false;
  32. }
  33. value = node.Value;
  34. return true;
  35. }
  36. /// <summary>
  37. /// Returns the start addresses of the intervals whose start and end keys overlap the given range.
  38. /// </summary>
  39. /// <param name="start">Start of the range</param>
  40. /// <param name="end">End of the range</param>
  41. /// <param name="overlaps">Overlaps array to place results in</param>
  42. /// <param name="overlapCount">Index to start writing results into the array. Defaults to 0</param>
  43. /// <returns>Number of intervals found</returns>
  44. public int Get(K start, K end, ref K[] overlaps, int overlapCount = 0)
  45. {
  46. GetKeys(_root, start, end, ref overlaps, ref overlapCount);
  47. return overlapCount;
  48. }
  49. /// <summary>
  50. /// Adds a new interval into the tree whose start is <paramref name="start"/>, end is <paramref name="end"/> and value is <paramref name="value"/>.
  51. /// </summary>
  52. /// <param name="start">Start of the range to add</param>
  53. /// <param name="end">End of the range to insert</param>
  54. /// <param name="value">Value to add</param>
  55. /// <param name="updateFactoryCallback">Optional factory used to create a new value if <paramref name="start"/> is already on the tree</param>
  56. /// <exception cref="ArgumentNullException"><paramref name="value"/> is null</exception>
  57. /// <returns>True if the value was added, false if the start key was already in the dictionary</returns>
  58. public bool AddOrUpdate(K start, K end, V value, Func<K, V, V> updateFactoryCallback)
  59. {
  60. if (value == null)
  61. {
  62. throw new ArgumentNullException(nameof(value));
  63. }
  64. return BSTInsert(start, end, value, updateFactoryCallback, out IntervalTreeNode<K, V> node);
  65. }
  66. /// <summary>
  67. /// Gets an existing or adds a new interval into the tree whose start is <paramref name="start"/>, end is <paramref name="end"/> and value is <paramref name="value"/>.
  68. /// </summary>
  69. /// <param name="start">Start of the range to add</param>
  70. /// <param name="end">End of the range to insert</param>
  71. /// <param name="value">Value to add</param>
  72. /// <exception cref="ArgumentNullException"><paramref name="value"/> is null</exception>
  73. /// <returns><paramref name="value"/> if <paramref name="start"/> is not yet on the tree, or the existing value otherwise</returns>
  74. public V GetOrAdd(K start, K end, V value)
  75. {
  76. if (value == null)
  77. {
  78. throw new ArgumentNullException(nameof(value));
  79. }
  80. BSTInsert(start, end, value, null, out IntervalTreeNode<K, V> node);
  81. return node.Value;
  82. }
  83. /// <summary>
  84. /// Removes a value from the tree, searching for it with <paramref name="key"/>.
  85. /// </summary>
  86. /// <param name="key">Key of the node to remove</param>
  87. /// <returns>Number of deleted values</returns>
  88. public int Remove(K key)
  89. {
  90. int removed = Delete(key);
  91. _count -= removed;
  92. return removed;
  93. }
  94. /// <summary>
  95. /// Adds all the nodes in the dictionary into <paramref name="list"/>.
  96. /// </summary>
  97. /// <returns>A list of all values sorted by Key Order</returns>
  98. public List<V> AsList()
  99. {
  100. List<V> list = new List<V>();
  101. AddToList(_root, list);
  102. return list;
  103. }
  104. #endregion
  105. #region Private Methods (BST)
  106. /// <summary>
  107. /// Adds all values that are children of or contained within <paramref name="node"/> into <paramref name="list"/>, in Key Order.
  108. /// </summary>
  109. /// <param name="node">The node to search for values within</param>
  110. /// <param name="list">The list to add values to</param>
  111. private void AddToList(IntervalTreeNode<K, V> node, List<V> list)
  112. {
  113. if (node == null)
  114. {
  115. return;
  116. }
  117. AddToList(node.Left, list);
  118. list.Add(node.Value);
  119. AddToList(node.Right, list);
  120. }
  121. /// <summary>
  122. /// Retrieve the node reference whose key is <paramref name="key"/>, or null if no such node exists.
  123. /// </summary>
  124. /// <param name="key">Key of the node to get</param>
  125. /// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
  126. /// <returns>Node reference in the tree</returns>
  127. private IntervalTreeNode<K, V> GetNode(K key)
  128. {
  129. if (key == null)
  130. {
  131. throw new ArgumentNullException(nameof(key));
  132. }
  133. IntervalTreeNode<K, V> node = _root;
  134. while (node != null)
  135. {
  136. int cmp = key.CompareTo(node.Start);
  137. if (cmp < 0)
  138. {
  139. node = node.Left;
  140. }
  141. else if (cmp > 0)
  142. {
  143. node = node.Right;
  144. }
  145. else
  146. {
  147. return node;
  148. }
  149. }
  150. return null;
  151. }
  152. /// <summary>
  153. /// Retrieve all keys that overlap the given start and end keys.
  154. /// </summary>
  155. /// <param name="start">Start of the range</param>
  156. /// <param name="end">End of the range</param>
  157. /// <param name="overlaps">Overlaps array to place results in</param>
  158. /// <param name="overlapCount">Overlaps count to update</param>
  159. private void GetKeys(IntervalTreeNode<K, V> node, K start, K end, ref K[] overlaps, ref int overlapCount)
  160. {
  161. if (node == null || start.CompareTo(node.Max) >= 0)
  162. {
  163. return;
  164. }
  165. GetKeys(node.Left, start, end, ref overlaps, ref overlapCount);
  166. bool endsOnRight = end.CompareTo(node.Start) > 0;
  167. if (endsOnRight)
  168. {
  169. if (start.CompareTo(node.End) < 0)
  170. {
  171. if (overlaps.Length >= overlapCount)
  172. {
  173. Array.Resize(ref overlaps, overlapCount + ArrayGrowthSize);
  174. }
  175. overlaps[overlapCount++] = node.Start;
  176. }
  177. GetKeys(node.Right, start, end, ref overlaps, ref overlapCount);
  178. }
  179. }
  180. /// <summary>
  181. /// Propagate an increase in max value starting at the given node, heading up the tree.
  182. /// This should only be called if the max increases - not for rebalancing or removals.
  183. /// </summary>
  184. /// <param name="node">The node to start propagating from</param>
  185. private void PropagateIncrease(IntervalTreeNode<K, V> node)
  186. {
  187. K max = node.Max;
  188. IntervalTreeNode<K, V> ptr = node;
  189. while ((ptr = ptr.Parent) != null)
  190. {
  191. if (max.CompareTo(ptr.Max) > 0)
  192. {
  193. ptr.Max = max;
  194. }
  195. else
  196. {
  197. break;
  198. }
  199. }
  200. }
  201. /// <summary>
  202. /// Propagate recalculating max value starting at the given node, heading up the tree.
  203. /// This fully recalculates the max value from all children when there is potential for it to decrease.
  204. /// </summary>
  205. /// <param name="node">The node to start propagating from</param>
  206. private void PropagateFull(IntervalTreeNode<K, V> node)
  207. {
  208. IntervalTreeNode<K, V> ptr = node;
  209. do
  210. {
  211. K max = ptr.End;
  212. if (ptr.Left != null && ptr.Left.Max.CompareTo(max) > 0)
  213. {
  214. max = ptr.Left.Max;
  215. }
  216. if (ptr.Right != null && ptr.Right.Max.CompareTo(max) > 0)
  217. {
  218. max = ptr.Right.Max;
  219. }
  220. ptr.Max = max;
  221. } while ((ptr = ptr.Parent) != null);
  222. }
  223. /// <summary>
  224. /// Insertion Mechanism for the interval tree. Similar to a BST insert, with the start of the range as the key.
  225. /// Iterates the tree starting from the root and inserts a new node where all children in the left subtree are less than <paramref name="start"/>, and all children in the right subtree are greater than <paramref name="start"/>.
  226. /// Each node can contain multiple values, and has an end address which is the maximum of all those values.
  227. /// Post insertion, the "max" value of the node and all parents are updated.
  228. /// </summary>
  229. /// <param name="start">Start of the range to insert</param>
  230. /// <param name="end">End of the range to insert</param>
  231. /// <param name="value">Value to insert</param>
  232. /// <param name="updateFactoryCallback">Optional factory used to create a new value if <paramref name="start"/> is already on the tree</param>
  233. /// <param name="outNode">Node that was inserted or modified</param>
  234. /// <returns>True if <paramref name="start"/> was not yet on the tree, false otherwise</returns>
  235. private bool BSTInsert(K start, K end, V value, Func<K, V, V> updateFactoryCallback, out IntervalTreeNode<K, V> outNode)
  236. {
  237. IntervalTreeNode<K, V> parent = null;
  238. IntervalTreeNode<K, V> node = _root;
  239. while (node != null)
  240. {
  241. parent = node;
  242. int cmp = start.CompareTo(node.Start);
  243. if (cmp < 0)
  244. {
  245. node = node.Left;
  246. }
  247. else if (cmp > 0)
  248. {
  249. node = node.Right;
  250. }
  251. else
  252. {
  253. outNode = node;
  254. if (updateFactoryCallback != null)
  255. {
  256. // Replace
  257. node.Value = updateFactoryCallback(start, node.Value);
  258. int endCmp = end.CompareTo(node.End);
  259. if (endCmp > 0)
  260. {
  261. node.End = end;
  262. if (end.CompareTo(node.Max) > 0)
  263. {
  264. node.Max = end;
  265. PropagateIncrease(node);
  266. RestoreBalanceAfterInsertion(node);
  267. }
  268. }
  269. else if (endCmp < 0)
  270. {
  271. node.End = end;
  272. PropagateFull(node);
  273. }
  274. }
  275. return false;
  276. }
  277. }
  278. IntervalTreeNode<K, V> newNode = new IntervalTreeNode<K, V>(start, end, value, parent);
  279. if (newNode.Parent == null)
  280. {
  281. _root = newNode;
  282. }
  283. else if (start.CompareTo(parent.Start) < 0)
  284. {
  285. parent.Left = newNode;
  286. }
  287. else
  288. {
  289. parent.Right = newNode;
  290. }
  291. PropagateIncrease(newNode);
  292. _count++;
  293. RestoreBalanceAfterInsertion(newNode);
  294. outNode = newNode;
  295. return true;
  296. }
  297. /// <summary>
  298. /// Removes the value from the dictionary after searching for it with <paramref name="key"/>.
  299. /// </summary>
  300. /// <param name="key">Key to search for</param>
  301. /// <returns>Number of deleted values</returns>
  302. private int Delete(K key)
  303. {
  304. IntervalTreeNode<K, V> nodeToDelete = GetNode(key);
  305. if (nodeToDelete == null)
  306. {
  307. return 0;
  308. }
  309. IntervalTreeNode<K, V> replacementNode;
  310. if (LeftOf(nodeToDelete) == null || RightOf(nodeToDelete) == null)
  311. {
  312. replacementNode = nodeToDelete;
  313. }
  314. else
  315. {
  316. replacementNode = PredecessorOf(nodeToDelete);
  317. }
  318. IntervalTreeNode<K, V> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
  319. if (tmp != null)
  320. {
  321. tmp.Parent = ParentOf(replacementNode);
  322. }
  323. if (ParentOf(replacementNode) == null)
  324. {
  325. _root = tmp;
  326. }
  327. else if (replacementNode == LeftOf(ParentOf(replacementNode)))
  328. {
  329. ParentOf(replacementNode).Left = tmp;
  330. }
  331. else
  332. {
  333. ParentOf(replacementNode).Right = tmp;
  334. }
  335. if (replacementNode != nodeToDelete)
  336. {
  337. nodeToDelete.Start = replacementNode.Start;
  338. nodeToDelete.Value = replacementNode.Value;
  339. nodeToDelete.End = replacementNode.End;
  340. nodeToDelete.Max = replacementNode.Max;
  341. }
  342. PropagateFull(replacementNode);
  343. if (tmp != null && ColorOf(replacementNode) == Black)
  344. {
  345. RestoreBalanceAfterRemoval(tmp);
  346. }
  347. return 1;
  348. }
  349. /// <summary>
  350. /// Returns the node with the largest key where <paramref name="node"/> is considered the root node.
  351. /// </summary>
  352. /// <param name="node">Root Node</param>
  353. /// <returns>Node with the maximum key in the tree of <paramref name="node"/></returns>
  354. private static IntervalTreeNode<K, V> Maximum(IntervalTreeNode<K, V> node)
  355. {
  356. IntervalTreeNode<K, V> tmp = node;
  357. while (tmp.Right != null)
  358. {
  359. tmp = tmp.Right;
  360. }
  361. return tmp;
  362. }
  363. /// <summary>
  364. /// Finds the node whose key is immediately less than <paramref name="node"/>.
  365. /// </summary>
  366. /// <param name="node">Node to find the predecessor of</param>
  367. /// <returns>Predecessor of <paramref name="node"/></returns>
  368. private static IntervalTreeNode<K, V> PredecessorOf(IntervalTreeNode<K, V> node)
  369. {
  370. if (node.Left != null)
  371. {
  372. return Maximum(node.Left);
  373. }
  374. IntervalTreeNode<K, V> parent = node.Parent;
  375. while (parent != null && node == parent.Left)
  376. {
  377. node = parent;
  378. parent = parent.Parent;
  379. }
  380. return parent;
  381. }
  382. #endregion
  383. #region Private Methods (RBL)
  384. private void RestoreBalanceAfterRemoval(IntervalTreeNode<K, V> balanceNode)
  385. {
  386. IntervalTreeNode<K, V> ptr = balanceNode;
  387. while (ptr != _root && ColorOf(ptr) == Black)
  388. {
  389. if (ptr == LeftOf(ParentOf(ptr)))
  390. {
  391. IntervalTreeNode<K, V> sibling = RightOf(ParentOf(ptr));
  392. if (ColorOf(sibling) == Red)
  393. {
  394. SetColor(sibling, Black);
  395. SetColor(ParentOf(ptr), Red);
  396. RotateLeft(ParentOf(ptr));
  397. sibling = RightOf(ParentOf(ptr));
  398. }
  399. if (ColorOf(LeftOf(sibling)) == Black && ColorOf(RightOf(sibling)) == Black)
  400. {
  401. SetColor(sibling, Red);
  402. ptr = ParentOf(ptr);
  403. }
  404. else
  405. {
  406. if (ColorOf(RightOf(sibling)) == Black)
  407. {
  408. SetColor(LeftOf(sibling), Black);
  409. SetColor(sibling, Red);
  410. RotateRight(sibling);
  411. sibling = RightOf(ParentOf(ptr));
  412. }
  413. SetColor(sibling, ColorOf(ParentOf(ptr)));
  414. SetColor(ParentOf(ptr), Black);
  415. SetColor(RightOf(sibling), Black);
  416. RotateLeft(ParentOf(ptr));
  417. ptr = _root;
  418. }
  419. }
  420. else
  421. {
  422. IntervalTreeNode<K, V> sibling = LeftOf(ParentOf(ptr));
  423. if (ColorOf(sibling) == Red)
  424. {
  425. SetColor(sibling, Black);
  426. SetColor(ParentOf(ptr), Red);
  427. RotateRight(ParentOf(ptr));
  428. sibling = LeftOf(ParentOf(ptr));
  429. }
  430. if (ColorOf(RightOf(sibling)) == Black && ColorOf(LeftOf(sibling)) == Black)
  431. {
  432. SetColor(sibling, Red);
  433. ptr = ParentOf(ptr);
  434. }
  435. else
  436. {
  437. if (ColorOf(LeftOf(sibling)) == Black)
  438. {
  439. SetColor(RightOf(sibling), Black);
  440. SetColor(sibling, Red);
  441. RotateLeft(sibling);
  442. sibling = LeftOf(ParentOf(ptr));
  443. }
  444. SetColor(sibling, ColorOf(ParentOf(ptr)));
  445. SetColor(ParentOf(ptr), Black);
  446. SetColor(LeftOf(sibling), Black);
  447. RotateRight(ParentOf(ptr));
  448. ptr = _root;
  449. }
  450. }
  451. }
  452. SetColor(ptr, Black);
  453. }
  454. private void RestoreBalanceAfterInsertion(IntervalTreeNode<K, V> balanceNode)
  455. {
  456. SetColor(balanceNode, Red);
  457. while (balanceNode != null && balanceNode != _root && ColorOf(ParentOf(balanceNode)) == Red)
  458. {
  459. if (ParentOf(balanceNode) == LeftOf(ParentOf(ParentOf(balanceNode))))
  460. {
  461. IntervalTreeNode<K, V> sibling = RightOf(ParentOf(ParentOf(balanceNode)));
  462. if (ColorOf(sibling) == Red)
  463. {
  464. SetColor(ParentOf(balanceNode), Black);
  465. SetColor(sibling, Black);
  466. SetColor(ParentOf(ParentOf(balanceNode)), Red);
  467. balanceNode = ParentOf(ParentOf(balanceNode));
  468. }
  469. else
  470. {
  471. if (balanceNode == RightOf(ParentOf(balanceNode)))
  472. {
  473. balanceNode = ParentOf(balanceNode);
  474. RotateLeft(balanceNode);
  475. }
  476. SetColor(ParentOf(balanceNode), Black);
  477. SetColor(ParentOf(ParentOf(balanceNode)), Red);
  478. RotateRight(ParentOf(ParentOf(balanceNode)));
  479. }
  480. }
  481. else
  482. {
  483. IntervalTreeNode<K, V> sibling = LeftOf(ParentOf(ParentOf(balanceNode)));
  484. if (ColorOf(sibling) == Red)
  485. {
  486. SetColor(ParentOf(balanceNode), Black);
  487. SetColor(sibling, Black);
  488. SetColor(ParentOf(ParentOf(balanceNode)), Red);
  489. balanceNode = ParentOf(ParentOf(balanceNode));
  490. }
  491. else
  492. {
  493. if (balanceNode == LeftOf(ParentOf(balanceNode)))
  494. {
  495. balanceNode = ParentOf(balanceNode);
  496. RotateRight(balanceNode);
  497. }
  498. SetColor(ParentOf(balanceNode), Black);
  499. SetColor(ParentOf(ParentOf(balanceNode)), Red);
  500. RotateLeft(ParentOf(ParentOf(balanceNode)));
  501. }
  502. }
  503. }
  504. SetColor(_root, Black);
  505. }
  506. private void RotateLeft(IntervalTreeNode<K, V> node)
  507. {
  508. if (node != null)
  509. {
  510. IntervalTreeNode<K, V> right = RightOf(node);
  511. node.Right = LeftOf(right);
  512. if (node.Right != null)
  513. {
  514. node.Right.Parent = node;
  515. }
  516. IntervalTreeNode<K, V> nodeParent = ParentOf(node);
  517. right.Parent = nodeParent;
  518. if (nodeParent == null)
  519. {
  520. _root = right;
  521. }
  522. else if (node == LeftOf(nodeParent))
  523. {
  524. nodeParent.Left = right;
  525. }
  526. else
  527. {
  528. nodeParent.Right = right;
  529. }
  530. right.Left = node;
  531. node.Parent = right;
  532. PropagateFull(node);
  533. }
  534. }
  535. private void RotateRight(IntervalTreeNode<K, V> node)
  536. {
  537. if (node != null)
  538. {
  539. IntervalTreeNode<K, V> left = LeftOf(node);
  540. node.Left = RightOf(left);
  541. if (node.Left != null)
  542. {
  543. node.Left.Parent = node;
  544. }
  545. IntervalTreeNode<K, V> nodeParent = ParentOf(node);
  546. left.Parent = nodeParent;
  547. if (nodeParent == null)
  548. {
  549. _root = left;
  550. }
  551. else if (node == RightOf(nodeParent))
  552. {
  553. nodeParent.Right = left;
  554. }
  555. else
  556. {
  557. nodeParent.Left = left;
  558. }
  559. left.Right = node;
  560. node.Parent = left;
  561. PropagateFull(node);
  562. }
  563. }
  564. #endregion
  565. #region Safety-Methods
  566. // These methods save memory by allowing us to forego sentinel nil nodes, as well as serve as protection against NullReferenceExceptions.
  567. /// <summary>
  568. /// Returns the color of <paramref name="node"/>, or Black if it is null.
  569. /// </summary>
  570. /// <param name="node">Node</param>
  571. /// <returns>The boolean color of <paramref name="node"/>, or black if null</returns>
  572. private static bool ColorOf(IntervalTreeNode<K, V> node)
  573. {
  574. return node == null || node.Color;
  575. }
  576. /// <summary>
  577. /// Sets the color of <paramref name="node"/> node to <paramref name="color"/>.
  578. /// <br></br>
  579. /// This method does nothing if <paramref name="node"/> is null.
  580. /// </summary>
  581. /// <param name="node">Node to set the color of</param>
  582. /// <param name="color">Color (Boolean)</param>
  583. private static void SetColor(IntervalTreeNode<K, V> node, bool color)
  584. {
  585. if (node != null)
  586. {
  587. node.Color = color;
  588. }
  589. }
  590. /// <summary>
  591. /// This method returns the left node of <paramref name="node"/>, or null if <paramref name="node"/> is null.
  592. /// </summary>
  593. /// <param name="node">Node to retrieve the left child from</param>
  594. /// <returns>Left child of <paramref name="node"/></returns>
  595. private static IntervalTreeNode<K, V> LeftOf(IntervalTreeNode<K, V> node)
  596. {
  597. return node?.Left;
  598. }
  599. /// <summary>
  600. /// This method returns the right node of <paramref name="node"/>, or null if <paramref name="node"/> is null.
  601. /// </summary>
  602. /// <param name="node">Node to retrieve the right child from</param>
  603. /// <returns>Right child of <paramref name="node"/></returns>
  604. private static IntervalTreeNode<K, V> RightOf(IntervalTreeNode<K, V> node)
  605. {
  606. return node?.Right;
  607. }
  608. /// <summary>
  609. /// Returns the parent node of <paramref name="node"/>, or null if <paramref name="node"/> is null.
  610. /// </summary>
  611. /// <param name="node">Node to retrieve the parent from</param>
  612. /// <returns>Parent of <paramref name="node"/></returns>
  613. private static IntervalTreeNode<K, V> ParentOf(IntervalTreeNode<K, V> node)
  614. {
  615. return node?.Parent;
  616. }
  617. #endregion
  618. public bool ContainsKey(K key)
  619. {
  620. return GetNode(key) != null;
  621. }
  622. public void Clear()
  623. {
  624. _root = null;
  625. _count = 0;
  626. }
  627. }
  628. /// <summary>
  629. /// Represents a node in the IntervalTree which contains start and end keys of type K, and a value of generic type V.
  630. /// </summary>
  631. /// <typeparam name="K">Key type of the node</typeparam>
  632. /// <typeparam name="V">Value type of the node</typeparam>
  633. class IntervalTreeNode<K, V>
  634. {
  635. public bool Color = true;
  636. public IntervalTreeNode<K, V> Left = null;
  637. public IntervalTreeNode<K, V> Right = null;
  638. public IntervalTreeNode<K, V> Parent = null;
  639. /// <summary>
  640. /// The start of the range.
  641. /// </summary>
  642. public K Start;
  643. /// <summary>
  644. /// The end of the range.
  645. /// </summary>
  646. public K End;
  647. /// <summary>
  648. /// The maximum end value of this node and all its children.
  649. /// </summary>
  650. public K Max;
  651. /// <summary>
  652. /// Value stored on this node.
  653. /// </summary>
  654. public V Value;
  655. public IntervalTreeNode(K start, K end, V value, IntervalTreeNode<K, V> parent)
  656. {
  657. Start = start;
  658. End = end;
  659. Max = end;
  660. Value = value;
  661. Parent = parent;
  662. }
  663. }
  664. }