Stacks in Python
What is a Stack?
Data structures play a key role in the world of programming. They help us organize our data in a way that can be used effectively. the stack is one of the simplest data structures. A Stack is similar to the pile of books, chairs, etc., in real life. And it follows the Last In/First Out (LIFO) principle. It is the simplest data structure. Stack in Python is an abstract data structure that stores elements linearly. Let's see the scenario with a real example
When we need the third book from the top, we have to remove the first two books from the top to take out the third book. Here, the topmost book goes last in the stack and comes first in the stack. The stack data structure follows the same Last In/First Out (LIFO) principle in programming.
Operations in Stack
There are mainly two operations in a stack
1. push (data)
Appends or pushes data onto the stack.
2.pop()
Removes or pops the topmost item from the stack. See illustrations below for push and pop operations.
We will equally write some helper functions that will help us get more information about the stack. Let's see them.
Peak()
Returns the topmost item in the stack.
is empty()
Returns whether the stack is empty or not.
Enough conceptual aspects of the Stack Data Structure. Let's get to the implementation without further ado. I guess you have python installed on your PC otherwise you can also try the online compiler otherwise you can run your codes online.
Stack Implementation in Python
The stack implementation is the simplest compared to other data structure implementations. We can implement a stack in many ways in Python. Let's see them all one by one.
#1. list
We are going to implement the stack using the list in a class. Let's see the step-by-step implementation of the stack.
Step1: Write a class called Stack.
class Stack:
pass
Step2: We need to keep the data in a list. Let's add an empty list in the Stack class with the name "item".
class Stack:
def __init__(self):
self.item = []
Step3: To push the items onto the stack, we need a method. Let's write a push method that takes data as an argument and append it to the items list.
class Stack:
def __init__(self):
self.item = []
def push(self, data):
self.item.append(data)
return data
Step4: Similarly, let's write the pop method that pops the topmost element out of the stack. We can use the pop method of list data type.
class Stack:
## ...
def pop(self):
return self.item.pop()
We have completed the stack implementation with the required operations. Now let's add the helper functions to get more information about the stack.
Step5: We can get the topmost element from the stack by using the negative index. The code
<span data-token-index="2" data-reactroot="">element[-1]</span>
#returns the last in the list. It is the topmost element in the stack in our case.
class Stack:
## ...
def peek(self):
return self.item[-1]
Step6: If the length of "item" in the list is 0, then the stack is empty. Let's write a method that returns whether "item" is empty or not.
class Stack:
## ...
def is_empty(self):
return len(self.item) == 0
We have completed the stack implementation using the list data type.
Oh! wait, we just implemented it. But I haven't seen how to use it.
How to use it then?
Come and see how to implement it. We need to create an object for the Stack class to use it. It's not serious. Let's do it first.
class Stack:
## ...
if __name__ == '__main__':
stack = Stack()
We have created the stack object and are ready to use it. Let's follow the steps below to test the stack operations.
Check whether the stack is empty or not using the is empty method. He should come back The real ones.
Push the numbers 1, 2, 3, 4, and 5 into the pile using the push method.
The is empty method must return False. Check that.
Print the topmost element using the peek method.
Pop the element from the stack using the pop method.
Check the peek element. It should return item 4.
Now pull out all the elements from the stack.
The is empty method must return The real ones. Check that.
Our stack implementation is complete if it passes all the steps above. Try writing the code for the above steps.
Did you write the code? No,
don't worry, check the code below.
class Stack:
def __init__(self):
self.item = []
def push(self, data):
self.item.append(data)
return data
def pop(self):
return self.item.pop()
def peek(self):
return self.item[-1]
def is_empty(self):
return len(self.item) == 0
if __name__ == '__main__':
stack = Stack()
## checking is_empty method -> true
print(stack.is_empty())
## pushing the item
stack.push(1)
stack.push(2)
stack.push(3)
stack.push(4)
stack.push(5)
## again checking is_empty method -> false
print(stack.is_empty())
## printing the topmost element of the stack -> 5
print(stack.peek())
## popping the topmost element -> 5
stack.pop()
## checking the topmost element using peek method -> 4
print(stack.peek())
## popping all the item
stack.pop()
stack.pop()
stack.pop()
stack.pop()
## checking the is_empty method for the last time -> true
print(stack.is_empty())
Hooray! we completed the stack implementation from scratch using the Data Type list. You will see the output as mentioned below if you run the code above.
True
False
5
4
True
We can directly use list data type as stack. The stack implementation above also helps you understand the stack implementation in other programming languages.
You can also check out these articles related to the list.
Let's see the built-in deque of the built-in collections module which can act as a stack.
# 2. deque collections
Stacks in Python is equally implemented using the deque collections. It is implemented as a two-ended queue. Since it supports adding and removing items from both ends. Therefore, we can use it as a stacker. We can make it follow the LIFO stack principle.
It is implemented using other data structures called doubly linked lists. Thus, the performance of inserting and deleting elements is consistent. Accessing the middle linked list elements took O(n) time. We can use it as a stacker because there is no need to access the middle elements from the stack.
Before implementing the stack, let's see the methods used to implement the stack in Python using the file.
append(data) - used to push data to the stack
popular() - used to remove the topmost element from the stack
There is no alternative method for peek and is empty. We can print the whole stack in python insted of peek method. Then we can use the len method to check if the stack is empty or not.
Let's implement the stack in Python using deque from the collections module.
from collections import deque
## creating deque object
stack = deque()
## checking whether stack is empty or not -> true
print(len(stack) == 0)
## pushing the item
stack.append(1)
stack.append(2)
stack.append(3)
stack.append(4)
stack.append(5)
## again checking whether stack is empty or not -> false
print(len(stack) == 0)
## printing the stack
print(stack)
## popping the topmost item -> 5
stack.pop()
## printing the stack
print(stack)
## popping all the item
stack.pop()
stack.pop()
stack.pop()
stack.pop()
## checking the whether stack is empty or not for the last time -> true
print(len(stack) == 0)
That's it. We learned how to implement stack in Python using the built-in collections module's deque. You will get the output as mentioned below if you run the above program.
True
False
deque([1, 2, 3, 4, 5])
deque([1, 2, 3, 4])
True
So far we have seen two ways to implement the stack in python Are there other ways to implement a stack? Yeah! Let's see the last way to implement a stack in this tutorial.
# 3. LifoQueue
Stacks in Python can be implemented with LifoQueue. The name of the LifoQueue blog itself says that it follows the LIFO principle. Therefore, we can use it as a stacker without a doubt. Its built-in module file's LifoQueue tiling provides convenient methods which are helpful in implementing the stack. Let's see them
put(data) - adds or pushes data to the queue get() - removes or pops the topmost item in the queue waiting empty() - returns whether the stack is empty or not qsize() - returns the queue length Let's implement the stack using LifoQueue from the file module.
from queue import LifoQueue
## creating LifoQueue object
stack = LifoQueue()
## checking whether stack is empty or not -> true
print(stack.empty())
## pushing the elements
stack.put(1)
stack.put(2)
stack.put(3)
stack.put(4)
stack.put(5)
## again checking whether stack is empty or not -> false
print(stack.empty())
## popping all the item
print(stack.get())
print(stack.get())
print(stack.get())
## checking the stack size
print("Size", stack.qsize())
print(stack.get())
print(stack.get())
## checking the whether stack is empty or not for the last time -> true
print(stack.empty())
You will get the below-mentioned output if you run the above program without modifying it.
True
False
5
4
3
Size 2
2
1
True
Application of Stacks in Python
Now you have enough knowledge of stacks to apply it to programming problems. Let's see a problem and solve it using a stack.
Given an expression, write a program to check whether parentheses, braces, braces are correctly balanced or not.
Let's see some examples.
Contribution: "[{}] ([])" Output: Balanced Contribution: "{[}] ([])" Output: Unbalanced
We can use the stack to solve the above problem. Let's see the steps to fix the problem.
Create a stack to store characters.
If the length of the expression is odd, then the expression is Unbalanced Iterate through the given expression.
If the current character is the opening bracket of ( or or [, then push it to stack it.
Else if the current character is a closing bracket ) or or ], then exit the stack.
If the skipped character matches the starting bracket, continue otherwise the brackets are unbalanced.
After the iteration, if the stack is empty, the equation is Balanced otherwise the equation is not Balanced. We can use the defined data type for bracket match checking.
## stack
class Stack:
def __init__(self):
self.item = []
def push(self, data):
self.item.append(data)
return data
def pop(self):
return self.item.pop()
def peek(self):
return self.item[-1]
def is_empty(self):
return len(self.item) == 0
def balance_check(expression):
## checking the length of the expression
if len(expression) % 2 != 0:
## not balanced if the length is odd
return False
## for checking
opening_brackets = set('([{')
pairs = set([ ('(',')'), ('[',']'), ('{','}') ])
## stack initialization
stack = Stack()
## iterating through the given expression
for bracket in expression:
## checking whether the current bracket is opened or not
if bracket in opening_brackets:
## adding to the stack
stack.push(bracket)
else:
## popping out the last bracket from the stack
popped_bracket = stack.pop()
## checking whether popped and current bracket pair
if (popped_bracket, bracket) not in pairs:
return False
return stack.is_empty()
if __name__ == '__main__':
if balance_check('[{}]([])'):
print("Balanced")
else:
print("Not Balanced")
if balance_check('{[}]([])'):
print("Balanced")
else:
print("Not Balanced")
We can use stacking to solve many more problems. The above problem is one of them. Try to apply the stack concept where you think it works best for you.
Conclusion
Yah! You have completed the tutorial. I hope you enjoyed the tutorial as much as I did making it. That's it for the tutorial.
Happy coder🙂 👨💻