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/. */
8 * A sorted tree with optimal access times, where recently-accessed elements
9 * are faster to access again.
12 #ifndef mozilla_SplayTree_h
13 #define mozilla_SplayTree_h
15 #include "mozilla/Assertions.h"
16 #include "mozilla/Attributes.h"
20 template<class T
, class C
>
27 template<class A
, class B
>
28 friend class SplayTree
;
44 * Class which represents a splay tree.
45 * Splay trees are balanced binary search trees for which search, insert and
46 * remove are all amortized O(log n), but where accessing a node makes it
47 * faster to access that node in the future.
49 * T indicates the type of tree elements, Comparator must have a static
50 * compare(const T&, const T&) method ordering the elements. The compare
51 * method must be free from side effects.
53 template<typename T
, class Comparator
>
68 T
* find(const T
& aValue
)
74 T
* last
= lookup(aValue
);
76 return Comparator::compare(aValue
, *last
) == 0 ? last
: nullptr;
79 void insert(T
* aValue
)
81 MOZ_ASSERT(!find(*aValue
), "Duplicate elements are not allowed.");
87 T
* last
= lookup(*aValue
);
88 int cmp
= Comparator::compare(*aValue
, *last
);
90 finishInsertion(last
, cmp
, aValue
);
93 T
* findOrInsert(const T
& aValue
);
95 T
* remove(const T
& aValue
)
97 T
* last
= lookup(aValue
);
98 MOZ_ASSERT(last
, "This tree must contain the element being removed.");
99 MOZ_ASSERT(Comparator::compare(aValue
, *last
) == 0);
101 // Splay the tree so that the item to remove is the root.
103 MOZ_ASSERT(last
== mRoot
);
105 // Find another node which can be swapped in for the root: either the
106 // rightmost child of the root's left, or the leftmost child of the
112 while (swap
->mRight
) {
115 swapChild
= swap
->mLeft
;
116 } else if (mRoot
->mRight
) {
117 swap
= mRoot
->mRight
;
118 while (swap
->mLeft
) {
121 swapChild
= swap
->mRight
;
128 // The selected node has at most one child, in swapChild. Detach it
129 // from the subtree by replacing it with that child.
130 if (swap
== swap
->mParent
->mLeft
) {
131 swap
->mParent
->mLeft
= swapChild
;
133 swap
->mParent
->mRight
= swapChild
;
136 swapChild
->mParent
= swap
->mParent
;
139 // Make the selected node the new root.
141 mRoot
->mParent
= nullptr;
142 mRoot
->mLeft
= last
->mLeft
;
143 mRoot
->mRight
= last
->mRight
;
145 mRoot
->mLeft
->mParent
= mRoot
;
148 mRoot
->mRight
->mParent
= mRoot
;
151 last
->mLeft
= nullptr;
152 last
->mRight
= nullptr;
158 MOZ_ASSERT(mRoot
, "No min to remove!");
167 // For testing purposes only.
168 void checkCoherency()
170 checkCoherency(mRoot
, nullptr);
175 * Returns the node in this comparing equal to |aValue|, or a node just
176 * greater or just less than |aValue| if there is no such node.
178 T
* lookup(const T
& aValue
)
180 MOZ_ASSERT(!empty());
186 int c
= Comparator::compare(aValue
, *node
);
198 void finishInsertion(T
* aLast
, int32_t aCmp
, T
* aNew
)
200 MOZ_ASSERT(aCmp
, "Nodes shouldn't be equal!");
202 T
** parentPointer
= (aCmp
< 0) ? &aLast
->mLeft
: &aLast
->mRight
;
203 MOZ_ASSERT(!*parentPointer
);
204 *parentPointer
= aNew
;
205 aNew
->mParent
= aLast
;
211 * Rotate the tree until |node| is at the root of the tree. Performing
212 * the rotations in this fashion preserves the amortized balancing of
219 while (aNode
!= mRoot
) {
220 T
* parent
= aNode
->mParent
;
221 if (parent
== mRoot
) {
224 MOZ_ASSERT(aNode
== mRoot
);
227 T
* grandparent
= parent
->mParent
;
228 if ((parent
->mLeft
== aNode
) == (grandparent
->mLeft
== parent
)) {
240 void rotate(T
* aNode
)
242 // Rearrange nodes so that aNode becomes the parent of its current
243 // parent, while preserving the sortedness of the tree.
244 T
* parent
= aNode
->mParent
;
245 if (parent
->mLeft
== aNode
) {
249 parent
->mLeft
= aNode
->mRight
;
251 aNode
->mRight
->mParent
= parent
;
253 aNode
->mRight
= parent
;
255 MOZ_ASSERT(parent
->mRight
== aNode
);
259 parent
->mRight
= aNode
->mLeft
;
261 aNode
->mLeft
->mParent
= parent
;
263 aNode
->mLeft
= parent
;
265 aNode
->mParent
= parent
->mParent
;
266 parent
->mParent
= aNode
;
267 if (T
* grandparent
= aNode
->mParent
) {
268 if (grandparent
->mLeft
== parent
) {
269 grandparent
->mLeft
= aNode
;
271 grandparent
->mRight
= aNode
;
278 T
* checkCoherency(T
* aNode
, T
* aMinimum
)
281 MOZ_RELEASE_ASSERT(!mRoot
->mParent
);
284 MOZ_RELEASE_ASSERT(!mRoot
);
287 if (!aNode
->mParent
) {
288 MOZ_RELEASE_ASSERT(aNode
== mRoot
);
291 MOZ_RELEASE_ASSERT(Comparator::compare(*aMinimum
, *aNode
) < 0);
294 MOZ_RELEASE_ASSERT(aNode
->mLeft
->mParent
== aNode
);
295 T
* leftMaximum
= checkCoherency(aNode
->mLeft
, aMinimum
);
296 MOZ_RELEASE_ASSERT(Comparator::compare(*leftMaximum
, *aNode
) < 0);
299 MOZ_RELEASE_ASSERT(aNode
->mRight
->mParent
== aNode
);
300 return checkCoherency(aNode
->mRight
, aNode
);
305 SplayTree(const SplayTree
&) = delete;
306 void operator=(const SplayTree
&) = delete;
309 template<typename T
, class Comparator
>
311 SplayTree
<T
, Comparator
>::findOrInsert(const T
& aValue
)
314 mRoot
= new T(aValue
);
318 T
* last
= lookup(aValue
);
319 int cmp
= Comparator::compare(aValue
, *last
);
324 T
* t
= new T(aValue
);
325 finishInsertion(last
, cmp
, t
);
329 } /* namespace mozilla */
331 #endif /* mozilla_SplayTree_h */