Skip to content

Commit c9f0696

Browse files
committed
ref: improve splay tree
1 parent 16df17c commit c9f0696

File tree

2 files changed

+92
-106
lines changed

2 files changed

+92
-106
lines changed

src/main/java/com/thealgorithms/datastructures/trees/SplayTree.java

Lines changed: 90 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -5,46 +5,27 @@
55

66
/**
77
* Implementation of a Splay Tree data structure.
8-
*
9-
* <p>
8+
*
109
* A splay tree is a self-adjusting binary search tree with the additional property
1110
* that recently accessed elements are quick to access again. It performs basic
1211
* operations such as insertion, deletion, and searching in O(log n) amortized time,
1312
* where n is the number of elements in the tree.
14-
* </p>
15-
*
16-
* <p>
13+
*
1714
* The key feature of splay trees is the splay operation, which moves a node closer
1815
* to the root of the tree when it is accessed. This operation helps to maintain
1916
* good balance and improves the overall performance of the tree. After performing
2017
* a splay operation, the accessed node becomes the new root of the tree.
21-
* </p>
22-
*
23-
* <p>
18+
*
2419
* Splay trees have applications in various areas, including caching, network routing,
2520
* and dynamic optimality analysis.
26-
* </p>
2721
*/
2822
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();
4126

4227
private Node root;
4328

44-
public SplayTree() {
45-
root = null;
46-
}
47-
4829
/**
4930
* Checks if the tree is empty.
5031
*
@@ -54,6 +35,69 @@ public boolean isEmpty() {
5435
return root == null;
5536
}
5637

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+
57101
/**
58102
* Zig operation.
59103
*
@@ -119,7 +163,7 @@ private Node rotateLeft(Node x) {
119163
* @param key The key to splay around.
120164
* @return The new root of the splayed subtree.
121165
*/
122-
private Node splay(Node root, int key) {
166+
private final Node splay(Node root, int key) {
123167
if (root == null || root.key == key) {
124168
return root;
125169
}
@@ -130,14 +174,10 @@ private Node splay(Node root, int key) {
130174
}
131175
// Zig-Zig case
132176
if (root.left.key > key) {
133-
// Recursive call to splay on grandchild
134177
root.left.left = splay(root.left.left, key);
135-
// Perform zig operation on parent
136178
root = rotateRight(root);
137-
} // Zig-Zag case
138-
else if (root.left.key < key) {
179+
} else if (root.left.key < key) {
139180
root.left.right = splay(root.left.right, key);
140-
// Perform zag operation on parent
141181
if (root.left.right != null) {
142182
root.left = rotateLeft(root.left);
143183
}
@@ -150,39 +190,18 @@ else if (root.left.key < key) {
150190
// Zag-Zag case
151191
if (root.right.key > key) {
152192
root.right.left = splay(root.right.left, key);
153-
// Perform zig operation on parent
154193
if (root.right.left != null) {
155194
root.right = rotateRight(root.right);
156195
}
157-
} // Zag-Zig case
158-
else if (root.right.key < key) {
196+
} else if (root.right.key < key) {
159197
root.right.right = splay(root.right.right, key);
160-
// Perform zag operation on parent
161198
root = rotateLeft(root);
162199
}
163200
return (root.right == null) ? root : rotateLeft(root);
164201
}
165202
}
166203

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) {
186205
if (root == null) {
187206
return new Node(key);
188207
}
@@ -192,65 +211,36 @@ private Node insertRec(Node root, int key) {
192211
} else if (key > root.key) {
193212
root.right = insertRec(root.right, key);
194213
} else {
195-
throw new IllegalArgumentException("Duplicate key: " + key);
214+
throw new DuplicateKeyException("Duplicate key: " + key);
196215
}
197216

198217
return root;
199218
}
200219

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+
}
210224
}
211225

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);
221229
}
230+
}
222231

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;
230236

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;
239241
}
240242
}
241243

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-
254244
public interface TreeTraversal {
255245
/**
256246
* Recursive function for a specific order traversal.
@@ -299,8 +289,4 @@ public void traverse(Node root, List<Integer> result) {
299289
}
300290
}
301291
}
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();
306292
}

src/test/java/com/thealgorithms/datastructures/trees/SplayTreeTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@ public void testDeleteNonExistent(int value) {
5757
@MethodSource("valuesToTest")
5858
public void testDeleteThrowsExceptionForEmptyTree(int value) {
5959
SplayTree tree = new SplayTree();
60-
assertThrows(IllegalArgumentException.class, () -> tree.delete(value));
60+
assertThrows(SplayTree.EmptyTreeException.class, () -> tree.delete(value));
6161
}
6262

6363
@ParameterizedTest
6464
@MethodSource("valuesToTest")
6565
public void testInsertThrowsExceptionForDuplicateKeys(int value) {
6666
SplayTree tree = createComplexTree();
67-
assertThrows(IllegalArgumentException.class, () -> tree.insert(value));
67+
assertThrows(SplayTree.DuplicateKeyException.class, () -> tree.insert(value));
6868
}
6969

7070
@ParameterizedTest

0 commit comments

Comments
 (0)