SplayTree.h 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* vim: set ts=8 sts=2 et sw=2 tw=80: */
  3. /* This Source Code Form is subject to the terms of the Mozilla Public
  4. * License, v. 2.0. If a copy of the MPL was not distributed with this
  5. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6. /**
  7. * A sorted tree with optimal access times, where recently-accessed elements
  8. * are faster to access again.
  9. */
  10. #ifndef mozilla_SplayTree_h
  11. #define mozilla_SplayTree_h
  12. #include "mozilla/Assertions.h"
  13. #include "mozilla/Attributes.h"
  14. namespace mozilla {
  15. template<class T, class C>
  16. class SplayTree;
  17. template<typename T>
  18. class SplayTreeNode
  19. {
  20. public:
  21. template<class A, class B>
  22. friend class SplayTree;
  23. SplayTreeNode()
  24. : mLeft(nullptr)
  25. , mRight(nullptr)
  26. , mParent(nullptr)
  27. {}
  28. private:
  29. T* mLeft;
  30. T* mRight;
  31. T* mParent;
  32. };
  33. /**
  34. * Class which represents a splay tree.
  35. * Splay trees are balanced binary search trees for which search, insert and
  36. * remove are all amortized O(log n), but where accessing a node makes it
  37. * faster to access that node in the future.
  38. *
  39. * T indicates the type of tree elements, Comparator must have a static
  40. * compare(const T&, const T&) method ordering the elements. The compare
  41. * method must be free from side effects.
  42. */
  43. template<typename T, class Comparator>
  44. class SplayTree
  45. {
  46. T* mRoot;
  47. public:
  48. constexpr SplayTree()
  49. : mRoot(nullptr)
  50. {}
  51. bool empty() const
  52. {
  53. return !mRoot;
  54. }
  55. T* find(const T& aValue)
  56. {
  57. if (empty()) {
  58. return nullptr;
  59. }
  60. T* last = lookup(aValue);
  61. splay(last);
  62. return Comparator::compare(aValue, *last) == 0 ? last : nullptr;
  63. }
  64. void insert(T* aValue)
  65. {
  66. MOZ_ASSERT(!find(*aValue), "Duplicate elements are not allowed.");
  67. if (!mRoot) {
  68. mRoot = aValue;
  69. return;
  70. }
  71. T* last = lookup(*aValue);
  72. int cmp = Comparator::compare(*aValue, *last);
  73. finishInsertion(last, cmp, aValue);
  74. return;
  75. }
  76. T* findOrInsert(const T& aValue);
  77. T* remove(const T& aValue)
  78. {
  79. T* last = lookup(aValue);
  80. MOZ_ASSERT(last, "This tree must contain the element being removed.");
  81. MOZ_ASSERT(Comparator::compare(aValue, *last) == 0);
  82. // Splay the tree so that the item to remove is the root.
  83. splay(last);
  84. MOZ_ASSERT(last == mRoot);
  85. // Find another node which can be swapped in for the root: either the
  86. // rightmost child of the root's left, or the leftmost child of the
  87. // root's right.
  88. T* swap;
  89. T* swapChild;
  90. if (mRoot->mLeft) {
  91. swap = mRoot->mLeft;
  92. while (swap->mRight) {
  93. swap = swap->mRight;
  94. }
  95. swapChild = swap->mLeft;
  96. } else if (mRoot->mRight) {
  97. swap = mRoot->mRight;
  98. while (swap->mLeft) {
  99. swap = swap->mLeft;
  100. }
  101. swapChild = swap->mRight;
  102. } else {
  103. T* result = mRoot;
  104. mRoot = nullptr;
  105. return result;
  106. }
  107. // The selected node has at most one child, in swapChild. Detach it
  108. // from the subtree by replacing it with that child.
  109. if (swap == swap->mParent->mLeft) {
  110. swap->mParent->mLeft = swapChild;
  111. } else {
  112. swap->mParent->mRight = swapChild;
  113. }
  114. if (swapChild) {
  115. swapChild->mParent = swap->mParent;
  116. }
  117. // Make the selected node the new root.
  118. mRoot = swap;
  119. mRoot->mParent = nullptr;
  120. mRoot->mLeft = last->mLeft;
  121. mRoot->mRight = last->mRight;
  122. if (mRoot->mLeft) {
  123. mRoot->mLeft->mParent = mRoot;
  124. }
  125. if (mRoot->mRight) {
  126. mRoot->mRight->mParent = mRoot;
  127. }
  128. return last;
  129. }
  130. T* removeMin()
  131. {
  132. MOZ_ASSERT(mRoot, "No min to remove!");
  133. T* min = mRoot;
  134. while (min->mLeft) {
  135. min = min->mLeft;
  136. }
  137. return remove(*min);
  138. }
  139. // For testing purposes only.
  140. void checkCoherency()
  141. {
  142. checkCoherency(mRoot, nullptr);
  143. }
  144. private:
  145. /**
  146. * Returns the node in this comparing equal to |aValue|, or a node just
  147. * greater or just less than |aValue| if there is no such node.
  148. */
  149. T* lookup(const T& aValue)
  150. {
  151. MOZ_ASSERT(!empty());
  152. T* node = mRoot;
  153. T* parent;
  154. do {
  155. parent = node;
  156. int c = Comparator::compare(aValue, *node);
  157. if (c == 0) {
  158. return node;
  159. } else if (c < 0) {
  160. node = node->mLeft;
  161. } else {
  162. node = node->mRight;
  163. }
  164. } while (node);
  165. return parent;
  166. }
  167. void finishInsertion(T* aLast, int32_t aCmp, T* aNew)
  168. {
  169. MOZ_ASSERT(aCmp, "Nodes shouldn't be equal!");
  170. T** parentPointer = (aCmp < 0) ? &aLast->mLeft : &aLast->mRight;
  171. MOZ_ASSERT(!*parentPointer);
  172. *parentPointer = aNew;
  173. aNew->mParent = aLast;
  174. splay(aNew);
  175. }
  176. /**
  177. * Rotate the tree until |node| is at the root of the tree. Performing
  178. * the rotations in this fashion preserves the amortized balancing of
  179. * the tree.
  180. */
  181. void splay(T* aNode)
  182. {
  183. MOZ_ASSERT(aNode);
  184. while (aNode != mRoot) {
  185. T* parent = aNode->mParent;
  186. if (parent == mRoot) {
  187. // Zig rotation.
  188. rotate(aNode);
  189. MOZ_ASSERT(aNode == mRoot);
  190. return;
  191. }
  192. T* grandparent = parent->mParent;
  193. if ((parent->mLeft == aNode) == (grandparent->mLeft == parent)) {
  194. // Zig-zig rotation.
  195. rotate(parent);
  196. rotate(aNode);
  197. } else {
  198. // Zig-zag rotation.
  199. rotate(aNode);
  200. rotate(aNode);
  201. }
  202. }
  203. }
  204. void rotate(T* aNode)
  205. {
  206. // Rearrange nodes so that aNode becomes the parent of its current
  207. // parent, while preserving the sortedness of the tree.
  208. T* parent = aNode->mParent;
  209. if (parent->mLeft == aNode) {
  210. // x y
  211. // y c ==> a x
  212. // a b b c
  213. parent->mLeft = aNode->mRight;
  214. if (aNode->mRight) {
  215. aNode->mRight->mParent = parent;
  216. }
  217. aNode->mRight = parent;
  218. } else {
  219. MOZ_ASSERT(parent->mRight == aNode);
  220. // x y
  221. // a y ==> x c
  222. // b c a b
  223. parent->mRight = aNode->mLeft;
  224. if (aNode->mLeft) {
  225. aNode->mLeft->mParent = parent;
  226. }
  227. aNode->mLeft = parent;
  228. }
  229. aNode->mParent = parent->mParent;
  230. parent->mParent = aNode;
  231. if (T* grandparent = aNode->mParent) {
  232. if (grandparent->mLeft == parent) {
  233. grandparent->mLeft = aNode;
  234. } else {
  235. grandparent->mRight = aNode;
  236. }
  237. } else {
  238. mRoot = aNode;
  239. }
  240. }
  241. T* checkCoherency(T* aNode, T* aMinimum)
  242. {
  243. if (mRoot) {
  244. MOZ_RELEASE_ASSERT(!mRoot->mParent);
  245. }
  246. if (!aNode) {
  247. MOZ_RELEASE_ASSERT(!mRoot);
  248. return nullptr;
  249. }
  250. if (!aNode->mParent) {
  251. MOZ_RELEASE_ASSERT(aNode == mRoot);
  252. }
  253. if (aMinimum) {
  254. MOZ_RELEASE_ASSERT(Comparator::compare(*aMinimum, *aNode) < 0);
  255. }
  256. if (aNode->mLeft) {
  257. MOZ_RELEASE_ASSERT(aNode->mLeft->mParent == aNode);
  258. T* leftMaximum = checkCoherency(aNode->mLeft, aMinimum);
  259. MOZ_RELEASE_ASSERT(Comparator::compare(*leftMaximum, *aNode) < 0);
  260. }
  261. if (aNode->mRight) {
  262. MOZ_RELEASE_ASSERT(aNode->mRight->mParent == aNode);
  263. return checkCoherency(aNode->mRight, aNode);
  264. }
  265. return aNode;
  266. }
  267. SplayTree(const SplayTree&) = delete;
  268. void operator=(const SplayTree&) = delete;
  269. };
  270. template<typename T, class Comparator>
  271. T*
  272. SplayTree<T, Comparator>::findOrInsert(const T& aValue)
  273. {
  274. if (!mRoot) {
  275. mRoot = new T(aValue);
  276. return mRoot;
  277. }
  278. T* last = lookup(aValue);
  279. int cmp = Comparator::compare(aValue, *last);
  280. if (!cmp) {
  281. return last;
  282. }
  283. T* t = new T(aValue);
  284. finishInsertion(last, cmp, t);
  285. return t;
  286. }
  287. } /* namespace mozilla */
  288. #endif /* mozilla_SplayTree_h */