SplayTree.h 7.5 KB

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