-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstack_nodes.py
234 lines (150 loc) · 4.96 KB
/
stack_nodes.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
from typing import Optional, Union
from typing import Iterable
from node import Node
class Stack:
"""A simple stack implementation."""
_size: int
_top: Optional[Node]
def __init__(self, *items):
"""Initializes the stack."""
self._top = None
self._size = 0
if len(items) > 0 and isinstance(items[0], Iterable):
items = items[0]
for item in items:
self.push(item)
def is_empty(self):
"""Checks if the stack is empty.
Returns:
bool: True if the stack is empty, False otherwise.
"""
return self._size <= 0
def clear(self):
"""Clears the stack."""
self._top = None
self._size = 0
def copy(self):
"""Returns a copy of the stack.
Caution: This method returns a shallow copy.
Returns:
Stack: A copy of the stack.
"""
new_stack = Stack()
new_stack._top = self._top
return new_stack
def depthcopy(self):
"""Returns a deep copy of the stack.
Returns:
Stack: A deep copy of the stack.
"""
new_stack = Stack()
new_stack._top = self._top.depthcopy()
new_stack._size = self._size
return new_stack
def extend(self, other: 'Stack'):
"""Extends the current stack with the items of the other stack.
Time complexity: O(n) where n is the length of the other stack.
Args:
other: The other stack to extend the current stack with.
"""
if other._top is None:
return None
bottom_node = other._top
while bottom_node.next is not None:
bottom_node = bottom_node.next
bottom_node.next = self._top
self._top = other._top
self._size += other._size
return None
def peek(self, raw: bool = False) -> Union[None, Node, object]:
"""Returns the top item of the stack.
Raises IndexError if the stack is empty.
Args:
raw: If True returns the Node, otherwise it will return the node value.
Returns:
object: The top item of the stack.
"""
if not self._top:
raise IndexError('The stack is empty.')
if raw:
return self._top
return self._top.value
def push(self, value: object):
"""Pushes an item onto the stack.
Time complexity: O(1)
Args:
item: The item to be pushed onto the stack.
"""
self._top = Node(value, self._top)
self._size += 1
def pop(self, raw: bool = False):
"""Pops an item off the stack.
Raises IndexError if the stack is empty.
Time complexity: O(1)
Args:
raw: If True returns the Node, otherwise it will return the node value.
Returns:
object: The item that was popped off the stack.
"""
if self._top is None:
raise IndexError('The stack is empty.')
temp = self._top
self._top = temp.next
self._size -= 1
if raw:
return temp
return temp.value
def __len__(self):
"""Returns the length of the stack.
Time complexity: O(1)
Returns:
int: The length of the stack.
"""
return self._size
def __str__(self) -> str:
"""Returns a string representation of the stack.
Time complexity: O(n)
Space complexity: O(n)
Returns:
str: A string representation of the stack.
"""
items = list(self)
return str(items)
def __contains__(self, item: object) -> bool:
"""Checks if the stack contains an item.
Args:
item: The item to check if the stack contains.
Returns:
bool: True if the stack contains the item, False otherwise.
"""
pointer = self._top
while pointer is not None:
if pointer.value == item:
return True
pointer = pointer.next
return False
def itervalues(self) -> Iterable:
"""Returns an iterator over the values of the stack.
Returns:
iterator: An iterator over the values of the stack.
"""
pointer = self._top
while pointer is not None:
yield pointer
pointer = pointer.next
def __iter__(self) -> Iterable:
"""Returns an iterator over the stack.
Returns:
iterator: An iterator over the stack.
"""
return self.itervalues()
def __add__(self, other):
"""Returns a new stack containing the items of both stacks.
Args:
other: The other stack to add to the current stack.
Returns:
Stack: A new stack containing the items of both stacks.
"""
new_stack = self.depthcopy()
new_stack.extend(other.depthcopy())
return new_stack