Skip to content

Commit d011ca8

Browse files
committed
Added splay trees algo .
1 parent 8303697 commit d011ca8

1 file changed

Lines changed: 222 additions & 0 deletions

File tree

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
"""
2+
Splay Tree implementation
3+
4+
A splay tree is a self-adjusting binary search tree where recently accessed
5+
elements are quick to access again. It performs basic operations such as
6+
insertion, look-up and removal in O(log n) amortized time.
7+
8+
Reference: https://en.wikipedia.org/wiki/Splay_tree
9+
"""
10+
11+
from __future__ import annotations
12+
from typing import Any, Iterator
13+
14+
15+
class SplayNode:
16+
"""Node class for Splay Tree"""
17+
18+
def __init__(self, data: Any) -> None:
19+
self.data = data
20+
self.left: SplayNode | None = None
21+
self.right: SplayNode | None = None
22+
23+
24+
class SplayTree:
25+
"""
26+
Splay Tree implementation with basic operations
27+
28+
>>> tree = SplayTree()
29+
>>> tree.insert(10)
30+
>>> tree.insert(5)
31+
>>> tree.insert(15)
32+
>>> tree.search(5)
33+
True
34+
>>> tree.search(20)
35+
False
36+
>>> tree.delete(5)
37+
>>> tree.search(5)
38+
False
39+
>>> list(tree.inorder())
40+
[10, 15]
41+
"""
42+
43+
def __init__(self) -> None:
44+
self.root: SplayNode | None = None
45+
46+
def _right_rotate(self, node: SplayNode) -> SplayNode:
47+
"""Right rotation for splay operation"""
48+
left_child = node.left
49+
if left_child is None:
50+
return node
51+
node.left = left_child.right
52+
left_child.right = node
53+
return left_child
54+
55+
def _left_rotate(self, node: SplayNode) -> SplayNode:
56+
"""Left rotation for splay operation"""
57+
right_child = node.right
58+
if right_child is None:
59+
return node
60+
node.right = right_child.left
61+
right_child.left = node
62+
return right_child
63+
64+
def _splay(self, root: SplayNode | None, key: Any) -> SplayNode | None:
65+
"""
66+
Splay operation to move accessed node to root
67+
"""
68+
if root is None or root.data == key:
69+
return root
70+
71+
# Key is in left subtree
72+
if key < root.data:
73+
if root.left is None:
74+
return root
75+
76+
# Zig-Zig (Left Left)
77+
if key < root.left.data:
78+
root.left.left = self._splay(root.left.left, key)
79+
root = self._right_rotate(root)
80+
81+
# Zig-Zag (Left Right)
82+
elif key > root.left.data:
83+
root.left.right = self._splay(root.left.right, key)
84+
if root.left.right:
85+
root.left = self._left_rotate(root.left)
86+
87+
return self._right_rotate(root) if root.left else root
88+
89+
# Key is in right subtree
90+
else:
91+
if root.right is None:
92+
return root
93+
94+
# Zag-Zag (Right Right)
95+
if key > root.right.data:
96+
root.right.right = self._splay(root.right.right, key)
97+
root = self._left_rotate(root)
98+
99+
# Zag-Zig (Right Left)
100+
elif key < root.right.data:
101+
root.right.left = self._splay(root.right.left, key)
102+
if root.right.left:
103+
root.right = self._right_rotate(root.right)
104+
105+
return self._left_rotate(root) if root.right else root
106+
107+
def insert(self, key: Any) -> None:
108+
"""
109+
Insert a key into the splay tree
110+
111+
>>> tree = SplayTree()
112+
>>> tree.insert(10)
113+
>>> tree.root.data
114+
10
115+
"""
116+
if self.root is None:
117+
self.root = SplayNode(key)
118+
return
119+
120+
self.root = self._splay(self.root, key)
121+
122+
if self.root.data == key:
123+
return # Key already exists
124+
125+
new_node = SplayNode(key)
126+
127+
if key < self.root.data:
128+
new_node.right = self.root
129+
new_node.left = self.root.left
130+
self.root.left = None
131+
else:
132+
new_node.left = self.root
133+
new_node.right = self.root.right
134+
self.root.right = None
135+
136+
self.root = new_node
137+
138+
def search(self, key: Any) -> bool:
139+
"""
140+
Search for a key in the splay tree
141+
142+
>>> tree = SplayTree()
143+
>>> tree.insert(10)
144+
>>> tree.search(10)
145+
True
146+
>>> tree.search(5)
147+
False
148+
"""
149+
if self.root is None:
150+
return False
151+
152+
self.root = self._splay(self.root, key)
153+
return self.root.data == key
154+
155+
def delete(self, key: Any) -> None:
156+
"""
157+
Delete a key from the splay tree
158+
159+
>>> tree = SplayTree()
160+
>>> tree.insert(10)
161+
>>> tree.insert(5)
162+
>>> tree.delete(5)
163+
>>> tree.search(5)
164+
False
165+
"""
166+
if self.root is None:
167+
return
168+
169+
self.root = self._splay(self.root, key)
170+
171+
if self.root.data != key:
172+
return # Key not found
173+
174+
if self.root.left is None:
175+
self.root = self.root.right
176+
elif self.root.right is None:
177+
self.root = self.root.left
178+
else:
179+
temp = self.root
180+
self.root = self._splay(self.root.left, key)
181+
self.root.right = temp.right
182+
183+
def inorder(self) -> Iterator[Any]:
184+
"""
185+
Inorder traversal of the splay tree
186+
187+
>>> tree = SplayTree()
188+
>>> tree.insert(10)
189+
>>> tree.insert(5)
190+
>>> tree.insert(15)
191+
>>> list(tree.inorder())
192+
[5, 10, 15]
193+
"""
194+
yield from self._inorder_helper(self.root)
195+
196+
def _inorder_helper(self, node: SplayNode | None) -> Iterator[Any]:
197+
"""Helper method for inorder traversal"""
198+
if node:
199+
yield from self._inorder_helper(node.left)
200+
yield node.data
201+
yield from self._inorder_helper(node.right)
202+
203+
204+
if __name__ == "__main__":
205+
import doctest
206+
doctest.testmod()
207+
208+
# Example usage
209+
tree = SplayTree()
210+
elements = [10, 5, 15, 3, 7, 12, 18]
211+
212+
print("Inserting elements:", elements)
213+
for elem in elements:
214+
tree.insert(elem)
215+
216+
print("Inorder traversal:", list(tree.inorder()))
217+
218+
print("Searching for 7:", tree.search(7))
219+
print("Searching for 20:", tree.search(20))
220+
221+
tree.delete(5)
222+
print("After deleting 5:", list(tree.inorder()))

0 commit comments

Comments
 (0)