forked from prabhupant/python-ds
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstack_using_linked_list.py
More file actions
173 lines (137 loc) · 4.44 KB
/
stack_using_linked_list.py
File metadata and controls
173 lines (137 loc) · 4.44 KB
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
"""
Stack Implementation Using Linked List
This module implements a Stack data structure using a LinkedList.
A stack is a linear data structure that follows the Last In First Out (LIFO) principle.
Operations:
- push: Add an element to the top of the stack
- pop: Remove the top element from the stack
Time Complexity:
- Push: O(1)
- Pop: O(1)
Space Complexity: O(n) where n is the number of elements in the stack
"""
from typing import Optional, Any, TypeVar
T = TypeVar('T') # Define a type variable for generic typing
class Element:
"""
A class representing an element in a linked list.
Attributes:
value: The value stored in the element
next: Reference to the next element in the linked list
"""
def __init__(self, value: Any):
"""
Initialize a new Element with a value.
Args:
value: The value to be stored in the element
"""
self.value = value
self.next: Optional['Element'] = None
class LinkedList:
"""
A class representing a singly linked list.
Attributes:
head: Reference to the first element in the linked list
"""
def __init__(self, head: Optional[Element] = None):
"""
Initialize a new LinkedList with an optional head element.
Args:
head: The first element of the linked list (default: None)
"""
self.head: Optional[Element] = head
def append(self, new_element: Element) -> None:
"""
Append a new element to the end of the linked list.
Args:
new_element: The element to append
"""
current = self.head
if self.head:
while current.next:
current = current.next
current.next = new_element
else:
self.head = new_element
def insert_first(self, new_element: Element) -> None:
"""
Insert a new element as the head of the LinkedList.
Args:
new_element: The element to insert at the beginning
"""
# Fetch the current head
current = self.head
new_element.next = current
self.head = new_element
def delete_first(self) -> Optional[Element]:
"""
Delete the first (head) element in the LinkedList and return it.
Returns:
The deleted element or None if the list is empty
"""
current = self.head
if current:
if current.next:
self.head = current.next
else:
self.head = None
return current
else:
return None
class Stack:
"""
A class representing a Stack data structure implemented using a LinkedList.
Attributes:
ll: The LinkedList used to store the stack elements
"""
def __init__(self, top: Optional[Element] = None):
"""
Initialize a new Stack with an optional top element.
Args:
top: The element to be placed at the top of the stack (default: None)
"""
self.ll = LinkedList(top)
def push(self, new_element: Element) -> None:
"""
Push (add) a new element onto the top of the stack.
Args:
new_element: The element to push onto the stack
"""
self.ll.insert_first(new_element)
def pop(self) -> Optional[Element]:
"""
Pop (remove) the first element off the top of the stack and return it.
Returns:
The element removed from the top of the stack or None if the stack is empty
"""
return self.ll.delete_first()
def is_empty(self) -> bool:
"""
Check if the stack is empty.
Returns:
True if the stack is empty, False otherwise
"""
return self.ll.head is None
if __name__ == "__main__":
# Test cases
# Set up some Elements
e1 = Element(1)
e2 = Element(2)
e3 = Element(3)
e4 = Element(4)
# Start setting up a Stack
stack = Stack(e1)
# Test stack functionality
stack.push(e2)
stack.push(e3)
print(f"Pop: {stack.pop().value}")
print(f"Pop: {stack.pop().value}")
print(f"Pop: {stack.pop().value}")
# Test empty stack
empty_result = stack.pop()
print(f"Pop from empty stack: {empty_result}")
# Test pushing after empty
stack.push(e4)
print(f"Pop after pushing to empty stack: {stack.pop().value}")
# Test is_empty method
print(f"Is stack empty? {stack.is_empty()}")