Introduction
A stack is a linear data structure that follows a particular order in which the operations are performed. The order may be LIFO (Last In First Out) or FILO (First In Last Out). LIFO implies that the element that is inserted last, comes out first and FILO implies that the element that is inserted first, comes out last.
A stack can be visualized as a pile of objects, such as plates, books, or cards. The object that is placed on the top of the pile is the first one to be removed, and the object that is placed at the bottom of the pile is the last one to be removed. The top of the stack is the only position where we can access, insert, or delete an element.
stack
Stacks are useful for many applications, such as evaluating expressions, function calls, backtracking, and undo/redo operations. These applications require storing and retrieving data in a reverse order, which can be easily achieved using stacks.
Basic operations
A stack supports four basic operations: push, pop, peek, and isEmpty. Some implementations may also support a fifth operation: isFull. These operations are defined as follows:
Push: This operation adds an element to the top of the stack. If the stack is full, then it is said to be an overflow condition.
Pop: This operation removes and returns the element from the top of the stack. If the stack is empty, then it is said to be an underflow condition.
Peek: This operation returns the element from the top of the stack without removing it. It can be used to check the current element in the stack.
IsEmpty: This operation returns true if the stack is empty, else false. It can be used to check whether there are any elements in the stack or not.
IsFull: This operation returns true if the stack is full, else false. It can be used to check whether there is any space left in the stack or not.
Implementation
A stack can be implemented using different data structures, such as arrays or linked lists. The choice of data structure depends on various factors, such as memory usage, performance, and ease of implementation. Here we will discuss two common ways of implementing a stack: using array and using linked list.
Using array
An array is a fixed-size container that stores elements in a contiguous block of memory. To implement a stack using an array, we need to maintain two variables: an array to store the elements and an integer to keep track of the top index of the stack. The top index initially points to -1, indicating that the stack is empty. When we push an element into the stack, we increment the top index and store the element at that position in the array. When we pop an element from the stack, we return the element at the top index and decrement it. The peek operation simply returns the element at the top index without changing it. The isEmpty operation checks whether the top index is -1 or not. The isFull operation checks whether the top index is equal to the size of the array minus one or not.
The advantage of using an array to implement a stack is that it is simple and fast. The disadvantage is that it has a fixed size and cannot grow or shrink dynamically. If we try to push an element into a full stack or pop an element from an empty stack, we will encounter an overflow or underflow error respectively.
[Ahrefs Keywords Explorer](^1^): This tool runs on a database of billions of keywords and lets you filter for keywords with low search volume and traffic potential. You can also use the "Questions" toggle to find long-tail keywords in the form of questions.
[Keyword Tool](^2^): This tool uses Google Autocomplete to generate over 750 long-tail keyword suggestions for any search term. You can also filter by language, country, and platform.
[Simple Long-Tail Keyword Generator](^3^): This tool allows you to enter your primary keywords and generate a list of keyword permutations based on modifiers, prefixes, and suffixes.
stack overflow error
stack exchange sites
stack data structure in java
stack vs heap memory
stack on gun safe
stack and tilt golf swing
stack the states game
stack skills review
stack on sentinel 18 gun safe
stack on 14 gun cabinet
stack effect in buildings
stack social coupon code
stack of books clipart
stack on elite 40 gun safe
stack on 22 gun safe
stack on tactical gun cabinet
stack of money png
stack of pancakes drawing
stack on biometric safe
stack on 8 gun cabinet
stack of papers gif
stack of books cake
stack on quick access safe
stack of money emoji
stack of books svg
stack on fire resistant safe
stack of pancakes calories
stack of money tattoo
stack of books transparent background
stack on 24 gun safe with electronic lock
stack of money clipart black and white
stack of books vector free download
stack on total defense 40 gun safe
stack of pancakes clipart black and white
stack of money wallpaper hd
stack on 10 gun cabinet dimensions
stack of books coloring page
stack on 18 gun convertible cabinet review
stack of money cake topper
stack on 36 gun safe weight
stack of books png images
stack on 16 gun safe with combination lock
stack of pancakes with syrup and butter
stack of money in hand drawing
stack on 22 gun security cabinet review
stack of books silhouette png
stack on 14 gun fire resistant security safe with electronic lock fs 14 mb e matte black review
Using linked list
A linked list is a dynamic-size container that stores elements in nodes that are linked together by pointers A linked list is a dynamic-size container that stores elements in nodes that are linked together by pointers. To implement a stack using a linked list, we need to maintain a pointer to the head node of the list, which represents the top of the stack. The head pointer initially points to null, indicating that the stack is empty. When we push an element into the stack, we create a new node with the element as its data and the head pointer as its next pointer, and then update the head pointer to point to the new node. When we pop an element from the stack, we return the data of the head node and update the head pointer to point to its next node. The peek operation simply returns the data of the head node without changing it. The isEmpty operation checks whether the head pointer is null or not. The isFull operation is not applicable for a linked list implementation, as it can grow or shrink dynamically depending on the available memory.
The advantage of using a linked list to implement a stack is that it has no fixed size and can accommodate any number of elements. The disadvantage is that it requires extra space for storing the pointers and it may be slower than an array implementation due to pointer manipulation and memory allocation/deallocation.
Examples
Now that we have learned how to implement a stack using different data structures, let us see some examples of how stacks can be used to solve various problems.
Evaluation of expressions
A common application of stacks is to evaluate arithmetic expressions that involve operators and operands. For example, given an expression like "2 + 3 * 4 - 5 / (6 + 7)", how can we compute its value? One way is to use two stacks: one for storing operands and one for storing operators. We can scan the expression from left to right and perform the following steps:
If we encounter an operand, we push it into the operand stack.
If we encounter an operator, we compare its precedence with the top operator in the operator stack. If the current operator has higher precedence, we push it into the operator stack. If the current operator has lower or equal precedence, we pop two operands from the operand stack and one operator from the operator stack, apply the operator on the operands, and push the result back into the operand stack. We repeat this step until either the operator stack is empty or the current operator has higher precedence than the top operator in the operator stack.
If we encounter an opening parenthesis '(', we push it into the operator stack.
If we encounter a closing parenthesis ')', we pop operators from the operator stack and apply them on operands from the operand stack until we reach an opening parenthesis '('. We then pop and discard the opening parenthesis from the operator stack.
When we reach the end of the expression, we pop operators from the operator stack and apply them on operands from the operand stack until the operator stack is empty. The final value in the operand stack is the result of the expression.
For example, let us evaluate the expression "2 + 3 * 4 - 5 / (6 + 7)" using this method. We will use two stacks: S1 for operands and S2 for operators. The table below shows the steps and the state of the stacks at each step.
Step Expression S1 S2 Action --- --- --- --- --- 1 2 + 3 * 4 - 5 / (6 + 7) Scan from left to right 2 2 + 3 * 4 - 5 / (6 + 7) 2 Push operand into S1 3 2 + 3 * 4 - 5 / (6 + 7) 2 + Push operator into S2 4 2 + 3 * 4 - 5 / (6 + 7) 2,3 + Push operand into S1 5 2 + 3 * 4 - 5 / (6 + 7) 2,3 +,* Push operator into S2 6 2 + 3 * 4 - 5 / (6 + 7) 2,3,4 +,* Push operand into S1 7 2 + 3 * 4 - 5 / (6 + 7) 2,12 - Pop two operands and one operator from stacks, apply *, push result into S1, push operator into S2 8 2 + 3 * 4 - 5 / (6 + 7) 2,12,5 - / Push operand into S1, push operator into S2 92+3*4-5/(6+7)2,12,5-,/,(Push operator into S2 102+3*4-5/(6+7)2,12,5,6-,/,(,+Push operand into S1, push operator into S2 112+3*4-5/(6+7)2,12,5,6-,/,(,+No action 122+3*4-5/(6+7)2,12,5,6,7-,/,(,+Push operand into S1 132+3*4-5/(6+7)2,12,5,13-,/Pop two operands and one operator from stacks, apply +, push result into S1, pop and discard ( from S2 142+3*4-5/(6+7)10-Pop two operands and one operator from stacks, apply /, push result into S1 1514,+-Pop two operands and one operator from stacks, apply -, push result into S1 1610Pop two operands and one operator from stacks, apply +, push result into S1 The final value in the operand stack is the result of the expression. In this case, it is 10.
Function calls and recursion
A stack can also be used to keep track of function calls and recursion. When a function is called by another function or by itself (recursion), the program needs to store some information about the current state of execution, such as the return address, the local variables, and the parameters. This information is stored in a data structure called a call stack or a function stack. Each function call creates a new entry or a frame in the call stack that contains the information related to that call. When a function returns or terminates, its frame is popped from the call stack and the control is transferred to the previous function in the call stack.
The call stack helps to maintain the order of execution and to resume the execution after a function call. It also helps to implement recursion, which is a technique of solving a problem by breaking it down into smaller subproblems of the same type. A recursive function calls itself with different arguments until it reaches a base case or a terminating condition. The call stack stores the intermediate results and parameters of each recursive call until it reaches the base case. Then it unwinds and returns the final result by popping the frames from the call stack.
For example, let us consider a recursive function that calculates the factorial of a given number. The factorial of a number n is defined as the product of all positive integers from 1 to n. It can be expressed as:
factorial(n) = n * factorial(n-1) if n > 0
factorial(n) = 1 if n = 0
The base case of this recursive function is when n is equal to 0, in which case it returns 1. Otherwise, it calls itself with n-1 as the argument and multiplies the result with n. The call stack stores the values of n and the return address for each recursive call until it reaches the base case. Then it returns the final result by popping the frames from the call stack.
For example, let us calculate the factorial of 5 using this recursive function. We will use a call stack to keep track of the function calls and their parameters. The table below shows the steps and the state of the call stack at each step.
Step Function call Call stack Action --- --- --- --- 1 factorial(5) Call factorial(5) 2 factorial(5) factorial(5) Push factorial(5) into call stack 3 factorial(4) factorial(5),factorial(4) Call factorial(4) and push it into call stack 4 factorial(3) factorial(5),factorial(4),factorial(3) Call factorial(3) and push it into call stack 5 factorial(2) factorial(5),factorial(4),factorial(3),factorial(2) Call factorial(2) and push it into call stack 6 factorial(1) factorial(5),factorial(4),factorial(3),factorial(2),factorial(1) Call factorial(1) and push it into call stack 7 factorial(0) factorial(5),factorial(4),factorial(3),factorial(2),factorial(1),factorial(0) Call factorial(0) and push it into call stack 8 return 1 factorial(5),factorial(4),factorial(3),factorial(2),factorial(1) Return 1 and pop factorial(0) from call stack 9 return 1 * 1 = 1 factorial(5),factorial(4),factorial(3),factorial(2) Return 1 * 1 = 1 and pop factorial(1) from call stack 10return 2 * 1 = 2factorial(5),factorial(4),factorial(3)Return 2 * 1 = 2 and pop factorial(2) from call stack 11return 3 * 2 = 6factorial(5),factorial(4)Return 3 * 2 = 6 and pop factorial (3) from call stack 12 return 4 * 6 = 24 factorial(5) Return 4 * 6 = 24 and pop factorial(4) from call stack 13 return 5 * 24 = 120 Return 5 * 24 = 120 and pop factorial(5) from call stack The final value returned by the recursive function is the result of the factorial of 5. In this case, it is 120.
Backtracking
Another application of stacks is to implement backtracking, which is a technique of exploring all possible solutions to a problem and choosing the best one. Backtracking involves making a series of choices and then undoing them if they lead to a dead end or a suboptimal solution. A stack can be used to store the current state of the problem and the choices made so far. When a choice leads to a dead end or a suboptimal solution, we can pop the stack and backtrack to the previous state and try a different choice.
One example of a problem that can be solved using backtracking is the N-Queens problem. The N-Queens problem is to place N queens on an N x N chessboard such that no two queens attack each other. A queen can attack another queen if they are on the same row, column, or diagonal. To solve this problem using backtracking, we can use a stack to store the positions of the queens placed so far. We can start by placing a queen in the first row and then move to the next row. For each row, we can try all possible columns and check if the current position is safe or not. If it is safe, we push it into the stack and move to the next row. If it is not safe, we try a different column. If we reach a row where no column is safe, we pop the stack and backtrack to the previous row and try a different column. We repeat this process until we either place N queens on the board or exhaust all possible choices.
For example, let us solve the 4-Queens problem using this method. We will use a stack to store the positions of the queens placed so far. The table below shows the steps and the state of the stack at each step.
Step Stack Board Action --- --- --- --- 1 . . . .. . . .. . . .. . . . Place a queen in the first row and first column 2 (0,0) Q . . .. . . .. . . .. . . . Push (0,0) into stack and move to second row 3 (0,0) Q . . .. Q . .. . . .. . . . Try placing a queen in the second row and first column 4 (0,0) Q . . .. Q . .. . Q .. . . . Try placing a queen in the third row and second column 5 (0,0) Q . . .. Q .. Q . .. . . . Try placing a queen in the fourth row and first column 6 (0,0) Q . . .. Q . .. . Q .. . Q . Check if the current position is safe or not 7 (0,0) Q . . .. Q . .. . Q .. . Q . No, it is not safe, as it is attacked by the queen in the first column 8 (0,0) Q . . .. Q . .. . Q .. . . Q Try placing a queen in the fourth row and second column 9 (0,0) Q . . .. Q . .. . Q .. . . Q Check if the current position is safe or not 10 (0,0) Q . . .. Q . .. . Q .. . . Q No, it is not safe, as it is attacked by the queen in the second column 11 (0,0) Q . . .. Q .. . Q .. . . . Try placing a queen in the fourth row and third column 12 (0,0) Q . . .. Q . .. . Q .. . . . Q Check if the current position is safe or not 13 (0,0) Q . . .. Q . .. . Q .. . . . Q No, it is not safe, as it is attacked by the queen in the third column 14 (0,0) Q . . .. Q . .. . Q .. Q . . . Try placing a queen in the fourth row and fourth column 15 (0,0) Q . . .. Q .. Q .. Q . . . Check if the current position is safe or not 16 (0,0) Q . . .. Q .. Q .. Q . No, it is not safe, as it is attacked by the queen in the first row 17 (0,0) Q .. Q .. Q .. Pop the stack and backtrack to the third row 18 (0,0),(1,1) Q .. . Q .. . . . .. Try placing a queen in the third row and third column 19 (0,0),(1,1),(2,2) Q .. . Q .. . . Q .. . . . Push (2,2) into stack and move to fourth row 20 (0,0),(1,1),(2,2) Q .. . Q .. . . Q .. Q . . Try placing a queen in the fourth row and first column 21 (0,0),(1,1),(2,2) Q .. . Q .. . . Q .. Q . . Check if the current position is safe or not 22 (0,0),(1,1),(2,2) Q .. . Q .. . . Q .. Q . . No, it is not safe, as it is attacked by the queen in the second column 23 (0,0),(1,1),(2,2) Q .. . Q .. . . Q .. . Q . Try placing a queen in the fourth row and second column 24 (0,0),(1,1),(2,2) Q .. . Q .. . . Q .. . Q . Check if the current position is safe or not 25 (0,0),(1,1),(2,2) Q .. . Q .. . . Q .. . Q . No, it is not safe, as it is attacked by the queen in the first column 26 (0,0),(1,1),(2,2) Q .. . Q .. . . Q .. . . Q Try placing a queen in the fourth row and third column 27 (0,0),(1,1),(2,2) Q
.user(Q)
.user(Q)
.user(Q)
.user(Q)
.user(Q)
.user(Q)
.user(Q)
.user(Q)
.user(Q)
.user(Q)
.user(Q)
.user(Q)
.user(Q)
.user(Q)Conclusion
In this article, we have learned about stacks, a type of data structure that follows the LIFO or FILO principle. We have seen how to implement a stack using different data structures such as arrays or linked lists. We have also seen some examples of how stacks can be used to solve various problems such as evaluation of expressions, function calls and recursion, and backtracking.
Stacks are useful for many applications that require storing and retrieving data in a reverse order. They can help us to simplify complex problems and to optimize the performance of our programs.
FAQs
What are some advantages and disadvantages of using stacks?
Some advantages of using FILO principle, which means that the element that is inserted last, comes out first. A queue follows the FIFO or LILO principle, which means that the element that is inserted first, comes out first. A stack can be visualized as a pile of objects, where the top of the stack is the only position where we can access, insert, or delete an element. A queue can be visualized as a line of objects, where the front of the queue is the position where we can delete an element and the rear of the queue is the position where we can insert an element.
How can we implement a queue using two stacks?
We can implement a queue using two stacks by using one stack for storing the elements in the queue and another stack for reversing the order of the elements. When we want to enqueue an element, we simply push it into the first stack. When we want to dequeue an element, we check if the second stack is empty or not. If it is empty, we pop all the elements from the first stack and push them into the second stack. Then we pop and return the top element from the second stack. If it is not empty, we just pop and return the top element from the second stack.
How can we implement a stack using one queue?
We can implement a stack using one queue by using a trick to reverse the order of the elements in the queue. When we want to push an element into the stack, we first enqueue it into the queue. Then we dequeue and enqueue all the elements in the queue except for the last one. This way, the last element becomes the first element in the queue, which represents the top of the stack. When we want to pop an element from the stack, we simply dequeue and return the first element from the queue.
44f88ac181
Comments