5
5
6
6
/**
7
7
* Implementation of a Splay Tree data structure.
8
- *
9
- * <p>
8
+ *
10
9
* A splay tree is a self-adjusting binary search tree with the additional property
11
10
* that recently accessed elements are quick to access again. It performs basic
12
11
* operations such as insertion, deletion, and searching in O(log n) amortized time,
13
12
* where n is the number of elements in the tree.
14
- * </p>
15
- *
16
- * <p>
13
+ *
17
14
* The key feature of splay trees is the splay operation, which moves a node closer
18
15
* to the root of the tree when it is accessed. This operation helps to maintain
19
16
* good balance and improves the overall performance of the tree. After performing
20
17
* a splay operation, the accessed node becomes the new root of the tree.
21
- * </p>
22
- *
23
- * <p>
18
+ *
24
19
* Splay trees have applications in various areas, including caching, network routing,
25
20
* and dynamic optimality analysis.
26
- * </p>
27
21
*/
28
22
public class SplayTree {
29
-
30
- private static class Node {
31
- final int key ;
32
- Node left ;
33
- Node right ;
34
-
35
- Node (int key ) {
36
- this .key = key ;
37
- left = null ;
38
- right = null ;
39
- }
40
- }
23
+ public static final TreeTraversal PRE_ORDER = new PreOrderTraversal ();
24
+ public static final TreeTraversal IN_ORDER = new InOrderTraversal ();
25
+ public static final TreeTraversal POST_ORDER = new PostOrderTraversal ();
41
26
42
27
private Node root ;
43
28
44
- public SplayTree () {
45
- root = null ;
46
- }
47
-
48
29
/**
49
30
* Checks if the tree is empty.
50
31
*
@@ -54,6 +35,69 @@ public boolean isEmpty() {
54
35
return root == null ;
55
36
}
56
37
38
+ /**
39
+ * Insert a key into the SplayTree.
40
+ *
41
+ * @param key The key to insert.
42
+ */
43
+ public final void insert (int key ) {
44
+ root = insertRec (root , key );
45
+ root = splay (root , key );
46
+ }
47
+
48
+ /**
49
+ * Search for a key in the SplayTree.
50
+ *
51
+ * @param key The key to search for.
52
+ * @return True if the key is found, otherwise false.
53
+ */
54
+ public boolean search (int key ) {
55
+ root = splay (root , key );
56
+ return root != null && root .key == key ;
57
+ }
58
+
59
+ /**
60
+ * Deletes a key from the SplayTree.
61
+ *
62
+ * @param key The key to delete.
63
+ * @throws IllegalArgumentException If the tree is empty.
64
+ */
65
+ public final void delete (int key ) {
66
+ if (isEmpty ()) {
67
+ throw new EmptyTreeException ("Cannot delete from an empty tree" );
68
+ }
69
+
70
+ // Splay the tree with the key to be deleted
71
+ root = splay (root , key );
72
+
73
+ // If the key is not found at the root, return without deleting
74
+ if (root .key != key ) {
75
+ return ;
76
+ }
77
+
78
+ // Handle deletion
79
+ if (root .left == null ) {
80
+ root = root .right ;
81
+ } else {
82
+ // Splay to bring the largest key in left subtree to root
83
+ Node temp = root ;
84
+ root = splay (root .left , key );
85
+ root .right = temp .right ;
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Perform a traversal of the SplayTree.
91
+ *
92
+ * @param traversal The type of traversal method.
93
+ * @return A list containing the keys in the specified traversal order.
94
+ */
95
+ public List <Integer > traverse (TreeTraversal traversal ) {
96
+ List <Integer > result = new LinkedList <>();
97
+ traversal .traverse (root , result );
98
+ return result ;
99
+ }
100
+
57
101
/**
58
102
* Zig operation.
59
103
*
@@ -119,7 +163,7 @@ private Node rotateLeft(Node x) {
119
163
* @param key The key to splay around.
120
164
* @return The new root of the splayed subtree.
121
165
*/
122
- private Node splay (Node root , int key ) {
166
+ private final Node splay (Node root , int key ) {
123
167
if (root == null || root .key == key ) {
124
168
return root ;
125
169
}
@@ -130,14 +174,10 @@ private Node splay(Node root, int key) {
130
174
}
131
175
// Zig-Zig case
132
176
if (root .left .key > key ) {
133
- // Recursive call to splay on grandchild
134
177
root .left .left = splay (root .left .left , key );
135
- // Perform zig operation on parent
136
178
root = rotateRight (root );
137
- } // Zig-Zag case
138
- else if (root .left .key < key ) {
179
+ } else if (root .left .key < key ) {
139
180
root .left .right = splay (root .left .right , key );
140
- // Perform zag operation on parent
141
181
if (root .left .right != null ) {
142
182
root .left = rotateLeft (root .left );
143
183
}
@@ -150,39 +190,18 @@ else if (root.left.key < key) {
150
190
// Zag-Zag case
151
191
if (root .right .key > key ) {
152
192
root .right .left = splay (root .right .left , key );
153
- // Perform zig operation on parent
154
193
if (root .right .left != null ) {
155
194
root .right = rotateRight (root .right );
156
195
}
157
- } // Zag-Zig case
158
- else if (root .right .key < key ) {
196
+ } else if (root .right .key < key ) {
159
197
root .right .right = splay (root .right .right , key );
160
- // Perform zag operation on parent
161
198
root = rotateLeft (root );
162
199
}
163
200
return (root .right == null ) ? root : rotateLeft (root );
164
201
}
165
202
}
166
203
167
- /**
168
- * Insert a key into the SplayTree.
169
- *
170
- * @param key The key to insert.
171
- */
172
- public void insert (int key ) {
173
- root = insertRec (root , key );
174
- root = splay (root , key );
175
- }
176
-
177
- /**
178
- * Recursive function to insert a key into a subtree.
179
- *
180
- * @param root The root of the subtree to insert the key into.
181
- * @param key The key to insert.
182
- * @return The root of the modified subtree after insertion.
183
- * @throws IllegalArgumentException If the key to be inserted already exists in the subtree.
184
- */
185
- private Node insertRec (Node root , int key ) {
204
+ private final Node insertRec (Node root , int key ) {
186
205
if (root == null ) {
187
206
return new Node (key );
188
207
}
@@ -192,65 +211,36 @@ private Node insertRec(Node root, int key) {
192
211
} else if (key > root .key ) {
193
212
root .right = insertRec (root .right , key );
194
213
} else {
195
- throw new IllegalArgumentException ("Duplicate key: " + key );
214
+ throw new DuplicateKeyException ("Duplicate key: " + key );
196
215
}
197
216
198
217
return root ;
199
218
}
200
219
201
- /**
202
- * Search for a key in the SplayTree.
203
- *
204
- * @param key The key to search for.
205
- * @return True if the key is found, otherwise false.
206
- */
207
- public boolean search (int key ) {
208
- root = splay (root , key );
209
- return root != null && root .key == key ;
220
+ public static class EmptyTreeException extends RuntimeException {
221
+ public EmptyTreeException (String message ) {
222
+ super (message );
223
+ }
210
224
}
211
225
212
- /**
213
- * Deletes a key from the SplayTree.
214
- *
215
- * @param key The key to delete.
216
- * @throws IllegalArgumentException If the tree is empty.
217
- */
218
- public void delete (int key ) {
219
- if (isEmpty ()) {
220
- throw new IllegalArgumentException ("Cannot delete from an empty tree" );
226
+ public static class DuplicateKeyException extends RuntimeException {
227
+ public DuplicateKeyException (String message ) {
228
+ super (message );
221
229
}
230
+ }
222
231
223
- // Splay the tree with the key to be deleted
224
- root = splay (root , key );
225
-
226
- // If the key is not found at the root, return without deleting
227
- if (root .key != key ) {
228
- return ;
229
- }
232
+ private static class Node {
233
+ final int key ;
234
+ Node left ;
235
+ Node right ;
230
236
231
- // Handle deletion
232
- if (root .left == null ) {
233
- root = root .right ;
234
- } else {
235
- // Splay to bring the largest key in left subtree to root
236
- Node temp = root ;
237
- root = splay (root .left , key );
238
- root .right = temp .right ;
237
+ Node (int key ) {
238
+ this .key = key ;
239
+ left = null ;
240
+ right = null ;
239
241
}
240
242
}
241
243
242
- /**
243
- * Perform a traversal of the SplayTree.
244
- *
245
- * @param traversal The type of traversal method.
246
- * @return A list containing the keys in the specified traversal order.
247
- */
248
- public List <Integer > traverse (TreeTraversal traversal ) {
249
- List <Integer > result = new LinkedList <>();
250
- traversal .traverse (root , result );
251
- return result ;
252
- }
253
-
254
244
public interface TreeTraversal {
255
245
/**
256
246
* Recursive function for a specific order traversal.
@@ -299,8 +289,4 @@ public void traverse(Node root, List<Integer> result) {
299
289
}
300
290
}
301
291
}
302
-
303
- public static final TreeTraversal PRE_ORDER = new PreOrderTraversal ();
304
- public static final TreeTraversal IN_ORDER = new InOrderTraversal ();
305
- public static final TreeTraversal POST_ORDER = new PostOrderTraversal ();
306
292
}
0 commit comments