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/NullPtr.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 bool 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 T
** parentPointer
= (cmp
< 0) ? &last
->mLeft
: &last
->mRight
;
91 MOZ_ASSERT(!*parentPointer
);
92 *parentPointer
= aValue
;
93 aValue
->mParent
= last
;
99 T
* remove(const T
& aValue
)
101 T
* last
= lookup(aValue
);
102 MOZ_ASSERT(last
, "This tree must contain the element being removed.");
103 MOZ_ASSERT(Comparator::compare(aValue
, *last
) == 0);
105 // Splay the tree so that the item to remove is the root.
107 MOZ_ASSERT(last
== mRoot
);
109 // Find another node which can be swapped in for the root: either the
110 // rightmost child of the root's left, or the leftmost child of the
116 while (swap
->mRight
) {
119 swapChild
= swap
->mLeft
;
120 } else if (mRoot
->mRight
) {
121 swap
= mRoot
->mRight
;
122 while (swap
->mLeft
) {
125 swapChild
= swap
->mRight
;
132 // The selected node has at most one child, in swapChild. Detach it
133 // from the subtree by replacing it with that child.
134 if (swap
== swap
->mParent
->mLeft
) {
135 swap
->mParent
->mLeft
= swapChild
;
137 swap
->mParent
->mRight
= swapChild
;
140 swapChild
->mParent
= swap
->mParent
;
143 // Make the selected node the new root.
145 mRoot
->mParent
= nullptr;
146 mRoot
->mLeft
= last
->mLeft
;
147 mRoot
->mRight
= last
->mRight
;
149 mRoot
->mLeft
->mParent
= mRoot
;
152 mRoot
->mRight
->mParent
= mRoot
;
160 MOZ_ASSERT(mRoot
, "No min to remove!");
169 // For testing purposes only.
170 void checkCoherency()
172 checkCoherency(mRoot
, nullptr);
177 * Returns the node in this comparing equal to |aValue|, or a node just
178 * greater or just less than |aValue| if there is no such node.
180 T
* lookup(const T
& aValue
)
182 MOZ_ASSERT(!empty());
188 int c
= Comparator::compare(aValue
, *node
);
201 * Rotate the tree until |node| is at the root of the tree. Performing
202 * the rotations in this fashion preserves the amortized balancing of
209 while (aNode
!= mRoot
) {
210 T
* parent
= aNode
->mParent
;
211 if (parent
== mRoot
) {
214 MOZ_ASSERT(aNode
== mRoot
);
217 T
* grandparent
= parent
->mParent
;
218 if ((parent
->mLeft
== aNode
) == (grandparent
->mLeft
== parent
)) {
230 void rotate(T
* aNode
)
232 // Rearrange nodes so that aNode becomes the parent of its current
233 // parent, while preserving the sortedness of the tree.
234 T
* parent
= aNode
->mParent
;
235 if (parent
->mLeft
== aNode
) {
239 parent
->mLeft
= aNode
->mRight
;
241 aNode
->mRight
->mParent
= parent
;
243 aNode
->mRight
= parent
;
245 MOZ_ASSERT(parent
->mRight
== aNode
);
249 parent
->mRight
= aNode
->mLeft
;
251 aNode
->mLeft
->mParent
= parent
;
253 aNode
->mLeft
= parent
;
255 aNode
->mParent
= parent
->mParent
;
256 parent
->mParent
= aNode
;
257 if (T
* grandparent
= aNode
->mParent
) {
258 if (grandparent
->mLeft
== parent
) {
259 grandparent
->mLeft
= aNode
;
261 grandparent
->mRight
= aNode
;
268 T
* checkCoherency(T
* aNode
, T
* aMinimum
)
271 MOZ_RELEASE_ASSERT(!mRoot
->mParent
);
274 MOZ_RELEASE_ASSERT(!mRoot
);
277 if (!aNode
->mParent
) {
278 MOZ_RELEASE_ASSERT(aNode
== mRoot
);
281 MOZ_RELEASE_ASSERT(Comparator::compare(*aMinimum
, *aNode
) < 0);
284 MOZ_RELEASE_ASSERT(aNode
->mLeft
->mParent
== aNode
);
285 T
* leftMaximum
= checkCoherency(aNode
->mLeft
, aMinimum
);
286 MOZ_RELEASE_ASSERT(Comparator::compare(*leftMaximum
, *aNode
) < 0);
289 MOZ_RELEASE_ASSERT(aNode
->mRight
->mParent
== aNode
);
290 return checkCoherency(aNode
->mRight
, aNode
);
295 SplayTree(const SplayTree
&) MOZ_DELETE
;
296 void operator=(const SplayTree
&) MOZ_DELETE
;
299 } /* namespace mozilla */
301 #endif /* mozilla_SplayTree_h */