SortedDictionary.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. #if NO_SORTEDDICTIONARY
  5. using System;
  6. using System.Diagnostics;
  7. //
  8. // Code ported from SortedDictionary.cs and SortedSet.cs in the BCL.
  9. // Unused portions have been removed for brevity.
  10. //
  11. namespace System.Collections.Generic
  12. {
  13. class SortedDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
  14. {
  15. private readonly TreeSet<KeyValuePair<TKey, TValue>> _set;
  16. public SortedDictionary()
  17. {
  18. _set = new TreeSet<KeyValuePair<TKey, TValue>>(new KeyValuePairComparer());
  19. }
  20. public void Add(TKey key, TValue value)
  21. {
  22. _set.Add(new KeyValuePair<TKey, TValue>(key, value));
  23. }
  24. public int Count
  25. {
  26. get
  27. {
  28. return _set.Count;
  29. }
  30. }
  31. public bool Remove(TKey key)
  32. {
  33. return _set.Remove(new KeyValuePair<TKey, TValue>(key, default(TValue)));
  34. }
  35. public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
  36. {
  37. return new Enumerator(this);
  38. }
  39. IEnumerator IEnumerable.GetEnumerator()
  40. {
  41. return GetEnumerator();
  42. }
  43. public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>
  44. {
  45. private readonly TreeSet<KeyValuePair<TKey, TValue>>.Enumerator _treeEnum;
  46. internal Enumerator(SortedDictionary<TKey, TValue> dictionary)
  47. {
  48. _treeEnum = dictionary._set.GetEnumerator();
  49. }
  50. public bool MoveNext()
  51. {
  52. return _treeEnum.MoveNext();
  53. }
  54. public void Dispose()
  55. {
  56. _treeEnum.Dispose();
  57. }
  58. public KeyValuePair<TKey, TValue> Current
  59. {
  60. get
  61. {
  62. return _treeEnum.Current;
  63. }
  64. }
  65. object IEnumerator.Current
  66. {
  67. get
  68. {
  69. return new KeyValuePair<TKey, TValue>(Current.Key, Current.Value);
  70. }
  71. }
  72. internal void Reset()
  73. {
  74. _treeEnum.Reset();
  75. }
  76. void IEnumerator.Reset()
  77. {
  78. _treeEnum.Reset();
  79. }
  80. }
  81. internal class KeyValuePairComparer : Comparer<KeyValuePair<TKey, TValue>>
  82. {
  83. private readonly IComparer<TKey> _keyComparer = Comparer<TKey>.Default;
  84. public override int Compare(KeyValuePair<TKey, TValue> x, KeyValuePair<TKey, TValue> y)
  85. {
  86. return _keyComparer.Compare(x.Key, y.Key);
  87. }
  88. }
  89. internal class TreeSet<T> : SortedSet<T>
  90. {
  91. public TreeSet(IComparer<T> comparer)
  92. : base(comparer)
  93. {
  94. }
  95. internal override bool AddIfNotPresent(T item)
  96. {
  97. var ret = base.AddIfNotPresent(item);
  98. if (!ret)
  99. {
  100. throw new ArgumentException("Duplicate entry added.");
  101. }
  102. return ret;
  103. }
  104. }
  105. }
  106. class SortedSet<T> : IEnumerable<T>
  107. {
  108. private readonly IComparer<T> _comparer;
  109. private Node _root;
  110. private int _count;
  111. private int _version;
  112. public SortedSet(IComparer<T> comparer)
  113. {
  114. _comparer = comparer;
  115. }
  116. public int Count
  117. {
  118. get
  119. {
  120. return _count;
  121. }
  122. }
  123. public bool Add(T item)
  124. {
  125. return AddIfNotPresent(item);
  126. }
  127. internal virtual bool AddIfNotPresent(T item)
  128. {
  129. if (_root == null)
  130. {
  131. _root = new Node(item, false);
  132. _count = 1;
  133. _version++;
  134. return true;
  135. }
  136. //
  137. // Search for a node at bottom to insert the new node.
  138. // If we can guarantee the node we found is not a 4-node, it would be easy to do insertion.
  139. // We split 4-nodes along the search path.
  140. //
  141. Node current = _root;
  142. Node parent = null;
  143. Node grandParent = null;
  144. Node greatGrandParent = null;
  145. //
  146. // Even if we don't actually add to the set, we may be altering its structure (by doing rotations
  147. // and such). so update version to disable any enumerators/subsets working on it.
  148. //
  149. _version++;
  150. int order = 0;
  151. while (current != null)
  152. {
  153. order = _comparer.Compare(item, current.Item);
  154. if (order == 0)
  155. {
  156. // We could have changed root node to red during the search process.
  157. // We need to set it to black before we return.
  158. _root.IsRed = false;
  159. return false;
  160. }
  161. // split a 4-node into two 2-nodes
  162. if (Is4Node(current))
  163. {
  164. Split4Node(current);
  165. // We could have introduced two consecutive red nodes after split. Fix that by rotation.
  166. if (IsRed(parent))
  167. {
  168. InsertionBalance(current, ref parent, grandParent, greatGrandParent);
  169. }
  170. }
  171. greatGrandParent = grandParent;
  172. grandParent = parent;
  173. parent = current;
  174. current = (order < 0) ? current.Left : current.Right;
  175. }
  176. Debug.Assert(parent != null, "Parent node cannot be null here!");
  177. var node = new Node(item);
  178. if (order > 0)
  179. {
  180. parent.Right = node;
  181. }
  182. else
  183. {
  184. parent.Left = node;
  185. }
  186. //
  187. // The new node will be red, so we will need to adjust the colors if parent node is also red.
  188. //
  189. if (parent.IsRed)
  190. {
  191. InsertionBalance(node, ref parent, grandParent, greatGrandParent);
  192. }
  193. //
  194. // Root node is always black.
  195. //
  196. _root.IsRed = false;
  197. ++_count;
  198. return true;
  199. }
  200. public bool Remove(T item)
  201. {
  202. return DoRemove(item); // hack so it can be made non-virtual
  203. }
  204. internal virtual bool DoRemove(T item)
  205. {
  206. if (_root == null)
  207. {
  208. return false;
  209. }
  210. // Search for a node and then find its succesor.
  211. // Then copy the item from the succesor to the matching node and delete the successor.
  212. // If a node doesn't have a successor, we can replace it with its left child (if not empty.)
  213. // or delete the matching node.
  214. //
  215. // In top-down implementation, it is important to make sure the node to be deleted is not a 2-node.
  216. // Following code will make sure the node on the path is not a 2 Node.
  217. //
  218. // Even if we don't actually remove from the set, we may be altering its structure (by doing rotations
  219. // and such). so update version to disable any enumerators/subsets working on it.
  220. //
  221. _version++;
  222. Node current = _root;
  223. Node parent = null;
  224. Node grandParent = null;
  225. Node match = null;
  226. Node parentOfMatch = null;
  227. bool foundMatch = false;
  228. while (current != null)
  229. {
  230. if (Is2Node(current))
  231. { // fix up 2-Node
  232. if (parent == null)
  233. { // current is root. Mark it as red
  234. current.IsRed = true;
  235. }
  236. else
  237. {
  238. Node sibling = GetSibling(current, parent);
  239. if (sibling.IsRed)
  240. {
  241. // If parent is a 3-node, flip the orientation of the red link.
  242. // We can acheive this by a single rotation
  243. // This case is converted to one of other cased below.
  244. Debug.Assert(!parent.IsRed, "parent must be a black node!");
  245. if (parent.Right == sibling)
  246. {
  247. RotateLeft(parent);
  248. }
  249. else
  250. {
  251. RotateRight(parent);
  252. }
  253. parent.IsRed = true;
  254. sibling.IsRed = false; // parent's color
  255. // sibling becomes child of grandParent or root after rotation. Update link from grandParent or root
  256. ReplaceChildOfNodeOrRoot(grandParent, parent, sibling);
  257. // sibling will become grandParent of current node
  258. grandParent = sibling;
  259. if (parent == match)
  260. {
  261. parentOfMatch = sibling;
  262. }
  263. // update sibling, this is necessary for following processing
  264. sibling = (parent.Left == current) ? parent.Right : parent.Left;
  265. }
  266. Debug.Assert(sibling != null || sibling.IsRed == false, "sibling must not be null and it must be black!");
  267. if (Is2Node(sibling))
  268. {
  269. Merge2Nodes(parent, current, sibling);
  270. }
  271. else
  272. {
  273. // current is a 2-node and sibling is either a 3-node or a 4-node.
  274. // We can change the color of current to red by some rotation.
  275. TreeRotation rotation = RotationNeeded(parent, current, sibling);
  276. Node newGrandParent = null;
  277. switch (rotation)
  278. {
  279. case TreeRotation.RightRotation:
  280. Debug.Assert(parent.Left == sibling, "sibling must be left child of parent!");
  281. Debug.Assert(sibling.Left.IsRed, "Left child of sibling must be red!");
  282. sibling.Left.IsRed = false;
  283. newGrandParent = RotateRight(parent);
  284. break;
  285. case TreeRotation.LeftRotation:
  286. Debug.Assert(parent.Right == sibling, "sibling must be left child of parent!");
  287. Debug.Assert(sibling.Right.IsRed, "Right child of sibling must be red!");
  288. sibling.Right.IsRed = false;
  289. newGrandParent = RotateLeft(parent);
  290. break;
  291. case TreeRotation.RightLeftRotation:
  292. Debug.Assert(parent.Right == sibling, "sibling must be left child of parent!");
  293. Debug.Assert(sibling.Left.IsRed, "Left child of sibling must be red!");
  294. newGrandParent = RotateRightLeft(parent);
  295. break;
  296. case TreeRotation.LeftRightRotation:
  297. Debug.Assert(parent.Left == sibling, "sibling must be left child of parent!");
  298. Debug.Assert(sibling.Right.IsRed, "Right child of sibling must be red!");
  299. newGrandParent = RotateLeftRight(parent);
  300. break;
  301. }
  302. newGrandParent.IsRed = parent.IsRed;
  303. parent.IsRed = false;
  304. current.IsRed = true;
  305. ReplaceChildOfNodeOrRoot(grandParent, parent, newGrandParent);
  306. if (parent == match)
  307. {
  308. parentOfMatch = newGrandParent;
  309. }
  310. grandParent = newGrandParent;
  311. }
  312. }
  313. }
  314. // we don't need to compare any more once we found the match
  315. int order = foundMatch ? -1 : _comparer.Compare(item, current.Item);
  316. if (order == 0)
  317. {
  318. // save the matching node
  319. foundMatch = true;
  320. match = current;
  321. parentOfMatch = parent;
  322. }
  323. grandParent = parent;
  324. parent = current;
  325. if (order < 0)
  326. {
  327. current = current.Left;
  328. }
  329. else
  330. {
  331. current = current.Right; // continue the search in right sub tree after we find a match
  332. }
  333. }
  334. // move successor to the matching node position and replace links
  335. if (match != null)
  336. {
  337. ReplaceNode(match, parentOfMatch, parent, grandParent);
  338. --_count;
  339. }
  340. if (_root != null)
  341. {
  342. _root.IsRed = false;
  343. }
  344. return foundMatch;
  345. }
  346. public Enumerator GetEnumerator()
  347. {
  348. return new Enumerator(this);
  349. }
  350. IEnumerator<T> IEnumerable<T>.GetEnumerator()
  351. {
  352. return new Enumerator(this);
  353. }
  354. IEnumerator IEnumerable.GetEnumerator()
  355. {
  356. return new Enumerator(this);
  357. }
  358. private static Node GetSibling(Node node, Node parent)
  359. {
  360. if (parent.Left == node)
  361. {
  362. return parent.Right;
  363. }
  364. return parent.Left;
  365. }
  366. // After calling InsertionBalance, we need to make sure current and parent up-to-date.
  367. // It doesn't matter if we keep grandParent and greatGrantParent up-to-date
  368. // because we won't need to split again in the next node.
  369. // By the time we need to split again, everything will be correctly set.
  370. //
  371. private void InsertionBalance(Node current, ref Node parent, Node grandParent, Node greatGrandParent)
  372. {
  373. Debug.Assert(grandParent != null, "Grand parent cannot be null here!");
  374. bool parentIsOnRight = (grandParent.Right == parent);
  375. bool currentIsOnRight = (parent.Right == current);
  376. Node newChildOfGreatGrandParent;
  377. if (parentIsOnRight == currentIsOnRight)
  378. { // same orientation, single rotation
  379. newChildOfGreatGrandParent = currentIsOnRight ? RotateLeft(grandParent) : RotateRight(grandParent);
  380. }
  381. else
  382. { // different orientaton, double rotation
  383. newChildOfGreatGrandParent = currentIsOnRight ? RotateLeftRight(grandParent) : RotateRightLeft(grandParent);
  384. // current node now becomes the child of greatgrandparent
  385. parent = greatGrandParent;
  386. }
  387. // grand parent will become a child of either parent of current.
  388. grandParent.IsRed = true;
  389. newChildOfGreatGrandParent.IsRed = false;
  390. ReplaceChildOfNodeOrRoot(greatGrandParent, grandParent, newChildOfGreatGrandParent);
  391. }
  392. private static bool Is2Node(Node node)
  393. {
  394. Debug.Assert(node != null, "node cannot be null!");
  395. return IsBlack(node) && IsNullOrBlack(node.Left) && IsNullOrBlack(node.Right);
  396. }
  397. private static bool Is4Node(Node node)
  398. {
  399. return IsRed(node.Left) && IsRed(node.Right);
  400. }
  401. private static bool IsBlack(Node node)
  402. {
  403. return (node != null && !node.IsRed);
  404. }
  405. private static bool IsNullOrBlack(Node node)
  406. {
  407. return (node == null || !node.IsRed);
  408. }
  409. private static bool IsRed(Node node)
  410. {
  411. return (node != null && node.IsRed);
  412. }
  413. private static void Merge2Nodes(Node parent, Node child1, Node child2)
  414. {
  415. Debug.Assert(IsRed(parent), "parent must be be red");
  416. // combing two 2-nodes into a 4-node
  417. parent.IsRed = false;
  418. child1.IsRed = true;
  419. child2.IsRed = true;
  420. }
  421. // Replace the child of a parent node.
  422. // If the parent node is null, replace the root.
  423. private void ReplaceChildOfNodeOrRoot(Node parent, Node child, Node newChild)
  424. {
  425. if (parent != null)
  426. {
  427. if (parent.Left == child)
  428. {
  429. parent.Left = newChild;
  430. }
  431. else
  432. {
  433. parent.Right = newChild;
  434. }
  435. }
  436. else
  437. {
  438. _root = newChild;
  439. }
  440. }
  441. // Replace the matching node with its succesor.
  442. private void ReplaceNode(Node match, Node parentOfMatch, Node successor, Node parentOfSuccessor)
  443. {
  444. if (successor == match)
  445. { // this node has no successor, should only happen if right child of matching node is null.
  446. Debug.Assert(match.Right == null, "Right child must be null!");
  447. successor = match.Left;
  448. }
  449. else
  450. {
  451. Debug.Assert(parentOfSuccessor != null, "parent of successor cannot be null!");
  452. Debug.Assert(successor.Left == null, "Left child of succesor must be null!");
  453. Debug.Assert((successor.Right == null && successor.IsRed) || (successor.Right.IsRed && !successor.IsRed), "Succesor must be in valid state");
  454. if (successor.Right != null)
  455. {
  456. successor.Right.IsRed = false;
  457. }
  458. if (parentOfSuccessor != match)
  459. { // detach succesor from its parent and set its right child
  460. parentOfSuccessor.Left = successor.Right;
  461. successor.Right = match.Right;
  462. }
  463. successor.Left = match.Left;
  464. }
  465. if (successor != null)
  466. {
  467. successor.IsRed = match.IsRed;
  468. }
  469. ReplaceChildOfNodeOrRoot(parentOfMatch, match, successor);
  470. }
  471. internal void UpdateVersion()
  472. {
  473. ++_version;
  474. }
  475. private static Node RotateLeft(Node node)
  476. {
  477. var x = node.Right;
  478. node.Right = x.Left;
  479. x.Left = node;
  480. return x;
  481. }
  482. private static Node RotateLeftRight(Node node)
  483. {
  484. var child = node.Left;
  485. var grandChild = child.Right;
  486. node.Left = grandChild.Right;
  487. grandChild.Right = node;
  488. child.Right = grandChild.Left;
  489. grandChild.Left = child;
  490. return grandChild;
  491. }
  492. private static Node RotateRight(Node node)
  493. {
  494. var x = node.Left;
  495. node.Left = x.Right;
  496. x.Right = node;
  497. return x;
  498. }
  499. private static Node RotateRightLeft(Node node)
  500. {
  501. var child = node.Right;
  502. var grandChild = child.Left;
  503. node.Right = grandChild.Left;
  504. grandChild.Left = node;
  505. child.Left = grandChild.Right;
  506. grandChild.Right = child;
  507. return grandChild;
  508. }
  509. private static TreeRotation RotationNeeded(Node parent, Node current, Node sibling)
  510. {
  511. Debug.Assert(IsRed(sibling.Left) || IsRed(sibling.Right), "sibling must have at least one red child");
  512. if (IsRed(sibling.Left))
  513. {
  514. if (parent.Left == current)
  515. {
  516. return TreeRotation.RightLeftRotation;
  517. }
  518. return TreeRotation.RightRotation;
  519. }
  520. else
  521. {
  522. if (parent.Left == current)
  523. {
  524. return TreeRotation.LeftRotation;
  525. }
  526. return TreeRotation.LeftRightRotation;
  527. }
  528. }
  529. private static void Split4Node(Node node)
  530. {
  531. node.IsRed = true;
  532. node.Left.IsRed = false;
  533. node.Right.IsRed = false;
  534. }
  535. internal class Node
  536. {
  537. public bool IsRed;
  538. public T Item;
  539. public Node Left;
  540. public Node Right;
  541. public Node(T item)
  542. {
  543. // The default color will be red, we never need to create a black node directly.
  544. Item = item;
  545. IsRed = true;
  546. }
  547. public Node(T item, bool isRed)
  548. {
  549. // The default color will be red, we never need to create a black node directly.
  550. Item = item;
  551. IsRed = isRed;
  552. }
  553. }
  554. public struct Enumerator : IEnumerator<T>
  555. {
  556. private readonly SortedSet<T> _tree;
  557. private int _version;
  558. private readonly Stack<Node> _stack;
  559. private Node _current;
  560. internal Enumerator(SortedSet<T> set)
  561. {
  562. _tree = set;
  563. _version = _tree._version;
  564. // 2lg(n + 1) is the maximum height
  565. _stack = new Stack<Node>(2 * (int)SortedSet<T>.log2(set.Count + 1));
  566. _current = null;
  567. Intialize();
  568. }
  569. private void Intialize()
  570. {
  571. _current = null;
  572. Node node = _tree._root;
  573. Node next = null, other = null;
  574. while (node != null)
  575. {
  576. next = node.Left;
  577. other = node.Right;
  578. _stack.Push(node);
  579. node = next;
  580. }
  581. }
  582. public bool MoveNext()
  583. {
  584. if (_version != _tree._version)
  585. {
  586. throw new InvalidOperationException("Collection has changed during enumeration.");
  587. }
  588. if (_stack.Count == 0)
  589. {
  590. _current = null;
  591. return false;
  592. }
  593. _current = _stack.Pop();
  594. Node node = _current.Right;
  595. Node next = null, other = null;
  596. while (node != null)
  597. {
  598. next = node.Left;
  599. other = node.Right;
  600. _stack.Push(node);
  601. node = next;
  602. }
  603. return true;
  604. }
  605. public void Dispose()
  606. {
  607. }
  608. public T Current
  609. {
  610. get
  611. {
  612. if (_current != null)
  613. {
  614. return _current.Item;
  615. }
  616. return default(T);
  617. }
  618. }
  619. object IEnumerator.Current
  620. {
  621. get
  622. {
  623. if (_current == null)
  624. {
  625. throw new InvalidOperationException("Collection has changed during enumeration.");
  626. }
  627. return _current.Item;
  628. }
  629. }
  630. internal bool NotStartedOrEnded
  631. {
  632. get
  633. {
  634. return _current == null;
  635. }
  636. }
  637. internal void Reset()
  638. {
  639. if (_version != _tree._version)
  640. {
  641. throw new InvalidOperationException("Collection has changed during enumeration.");
  642. }
  643. _stack.Clear();
  644. Intialize();
  645. }
  646. void IEnumerator.Reset()
  647. {
  648. Reset();
  649. }
  650. }
  651. private static int log2(int value)
  652. {
  653. int c = 0;
  654. while (value > 0)
  655. {
  656. c++;
  657. value >>= 1;
  658. }
  659. return c;
  660. }
  661. }
  662. internal enum TreeRotation
  663. {
  664. LeftRotation = 1,
  665. RightRotation = 2,
  666. RightLeftRotation = 3,
  667. LeftRightRotation = 4,
  668. }
  669. }
  670. #endif