C# Stack with Examples
A stack is a fundamental data structure that follows the Last-In-First-Out (LIFO) concept. It is called a "stack" because it resembles a stack of objects where new items are always piled on top, and only the highest item may be accessed or removed. Programmers can utilise stacks for various purposes, but they come in handy for developing algorithms, managing memory, and tracing function calls.
Stacks are essential in programming because they are straightforward and effective for data management. The most recently inserted element is always the first to be accessed or removed since they offer an organised mechanism to store and retrieve elements.
The Stack class in C# allows you to:
- Push elements onto the top of the stack using the Push method.
- Pop the top element from the stack using the Pop method, which removes the element.
- Access the top element without removing it using the Peek method.
- Determine the number of elements in the stack using the Count property.
- Clear the stack by removing all elements using the Clear method.
Creating a stack
To create a new instance of a Stack in C#, the following syntax can be used:
Stack<T> stack = new Stack<T>();
The <T> represents the elements you want to store in the stack. Replace it with the desired data type, such as int, string, or a custom class.
Example for Creating an Empty Stack:
Stack<int> stack = new Stack<int>();
This creates an empty stack that can hold integers.
Example for Creating a Stack with Strings
Stack<string> stack = new Stack<string>(new[] { "apple", "banana", "mango" });
This creates a stack of strings with three initial elements: "apple", "banana", and "mango".
Adding Elements to the Stack
To add elements to the stack, you can use the Push method
Example:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Stack<int> stack = new Stack<int>();
stack.Push(10);
stack.Push(20);
stack.Push(30);
Console.WriteLine("Stack elements:");
while (stack.Count > 0)
{
int element = stack.Pop();
Console.WriteLine(element);
}
}
}
Output:
![C# Stack with Examples](https://static.tutorialandexample.com/csharp/csharp-stack-with-examples1.png)
Accessing and Removing Elements from the Stack
Peek and Pop are two methods the C# Stack class provides for accessing and removing components from the stack.
1. Peek method
You can access the top element of the stack using the Peek method without deleting it. The top-most object in the stack is returned.
Example:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Stack<string> stack = new Stack<string>();
stack.Push("Apple");
stack.Push("Banana");
stack.Push("Mango");
string topElement = stack.Peek();
Console.WriteLine("Top element: " + topElement);
}
}
Output:
![C# Stack with Examples](https://static.tutorialandexample.com/csharp/csharp-stack-with-examples2.png)
In this example, the Peek method retrieves the top element ("Mango") from the stack without removing it.
2. Pop method
The top element of the stack is removed and returned by the Pop function. It successfully takes the item out of the stack.
Example:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Stack<string> stack = new Stack<string>();
stack.Push("Apple");
stack.Push("Banana");
stack.Push("Mango");
string removedElement = stack.Pop();
Console.WriteLine("Removed element: " + removedElement);
}
}
Output:
![C# Stack with Examples](https://static.tutorialandexample.com/csharp/csharp-stack-with-examples3.png)
The top element ("Mango") is taken out and retrieved from the stack using the Pop function.
Checking Stack Size
The Stack class provides the Count property, which allows you to determine the number of elements in the stack.
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Stack<string> stack = new Stack<string>();
stack.Push("Apple");
stack.Push("Banana");
stack.Push("Cherry");
int size = stack.Count;
Console.WriteLine("Stack size: " + size);
}
}
Output:
![C# Stack with Examples](https://static.tutorialandexample.com/csharp/csharp-stack-with-examples4.png)
In this example, the Count property is used to get the number of elements in the stack, which is then printed to the console.
Checking whether the stack is empty or not
There are several techniques to determine whether a stack is empty in C#. Utilising the Count attribute of the Stack class is one typical method. The stack is empty if the count is zero. Another option is the IsEmpty method, which examines whether the stack is empty without first accessing the Count field.
Example:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Stack<int> stack = new Stack<int>();
// Method 1: Using the Count property
if (stack.Count == 0)
{
Console.WriteLine("Stack is empty");
}
// Method 2: Checking if Count is 0
if (stack.Count == 0)
{
Console.WriteLine("Stack is empty");
}
}
}
Output:
![C# Stack with Examples](https://static.tutorialandexample.com/csharp/csharp-stack-with-examples5.png)
Clearing the Stack:
Use the Clear function offered by the Stack class in C# to remove every element from a stack. This technique removes every single item and effectively clears the stack.
Stack-clearing example:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Stack<string> stack = new Stack<string>();
stack.Push("Apple");
stack.Push("Banana");
stack.Push("Mango");
Console.WriteLine("Stack before clearing:");
foreach (string element in stack)
{
Console.WriteLine(element);
}
stack.Clear();
Console.WriteLine("Stack after clearing:");
if (stack.Count == 0)
{
Console.WriteLine("Stack is empty");
}
}
}
Output:
![C# Stack with Examples](https://static.tutorialandexample.com/csharp/csharp-stack-with-examples6.png)
By utilising the Stack class in C#, developers can easily incorporate the functionality of a stack data structure into their programs, enabling efficient management of data and supporting various problem-solving techniques.
Applications
1. Parentheses Matching: Stacks are frequently used to verify the accuracy of brackets in mathematical or programming equations. It is simpler to spot mismatched or imbalanced brackets by stacking up opening brackets and popping them when they come across closing brackets.
using System;
using System.Collections.Generic;
public class ParenthesesMatcher
{
public static bool MatchParentheses(string input)
{
Stack<char> stack = new Stack<char>();
foreach (char c in input)
{
if (c == '(' || c == '[' || c == '{')
{
stack.Push(c);
}
else if (c == ')' || c == ']' || c == '}')
{
if (stack.Count == 0)
return false;
char top = stack.Pop();
if ((c == ')' && top != '(') || (c == ']' && top != '[') || (c == '}' && top != '{'))
return false;
}
}
return stack.Count == 0;
}
public static void Main()
{
string input = "((())())";
bool result = MatchParentheses(input);
Console.WriteLine("Parentheses Matching Result: " + result);
}
}
Output:
![C# Stack with Examples](https://static.tutorialandexample.com/csharp/csharp-stack-with-examples7.png)
2. Backtracking algorithms: Stacks are used by backtracking algorithms like depth-first search (DFS) to record the visited nodes or states. The stack retains the current path or decisions made when exploring a graph or looking for a solution, enabling the algorithm to go backwards.
using System;
using System.Collections.Generic;
class BacktrackingExample
{
static void Main()
{
// Example graph represented as an adjacency list
Dictionary<int, List<int>> graph = new Dictionary<int, List<int>>()
{
{ 1, new List<int>() { 2, 3 } },
{ 2, new List<int>() { 4 } },
{ 3, new List<int>() { 5 } },
{ 4, new List<int>() },
{ 5, new List<int>() { 6 } },
{ 6, new List<int>() },
};
int startNode = 1;
int targetNode = 6;
List<int> path = new List<int>();
HashSet<int> visited = new HashSet<int>();
Stack<int> stack = new Stack<int>();
stack.Push(startNode);
visited.Add(startNode);
while (stack.Count > 0)
{
int currentNode = stack.Pop();
path.Add(currentNode);
if (currentNode == targetNode)
{
Console.WriteLine("Path found: " + string.Join(" -> ", path));
return;
}
foreach (int neighbour in graph[currentNode])
{
if (!visited.Contains(neighbor))
{
stack.Push(neighbor);
visited.Add(neighbor);
}
}
}
Console.WriteLine("No path found.");
}
}
Output:
![C# Stack with Examples](https://static.tutorialandexample.com/csharp/csharp-stack-with-examples8.png)
Function Call Stack: Stacks are essential for managing function calls in programming languages. Every function call produces a stack frame and contains details such as local variables, return addresses, and function parameters. The stack ensures that after each successful function call, the program may return to the appropriate place.
Undo Operations: Many applications can undo and redo actions, allowing users to go back and apply modifications. Stacks are frequently used to store operations or states. Stacks enable effective undo and redo processes by pushing changes onto the undo stack and popping them for redo.
Browser History: Web browsers often employ a stack-like structure to keep track of previously visited online pages. The URL is added to the stack each time a user views a new page, allowing them to return by plucking URLs off the stack.
Expression Evaluation: Reverse Polish Notation (RPN) or postfix expressions are evaluated using stacks. The stack makes it easier to compute complicated mathematical expressions by pushing operands onto it and performing actions when they come across operators.
Function Call Stack Tracing: When debugging, stacks are essential for keeping track of function calls and determining the order in which code was executed. Stack traces give developers valuable details about the call hierarchy that aid in problem diagnosis and resolution.
Benefits of Utilising Stacks:
Simpleness: Stacks are a well-liked option for handling data in programming since they are straightforward to learn and use.
Last-In-First-Out (LIFO) Principle: The Last-In-First-Out (LIFO) principle of stacks fits well with various real-world situations, including undo operations, function call management, and backtracking algorithms.
Efficient Element Access: It is quick and easy to get at and modify elements in a stack. No matter how big the stack is, adding and removing items requires constant time O(1).
Memory Management: Stacks efficiently use memory by allocating a defined amount of memory for each element. As a result, dynamic memory allocation is no longer needed, and memory fragmentation is decreased.
Function Call Management: Stacks are frequently used to control function calls in programming languages. Every function call adds to the call stack, making it simple to follow the execution of programs and effectively manage memory.
Limitations of Stacks:
Fixed Size: Stacks have a fixed size, which means they can only hold a certain number of elements. Memory allocation problems or stack overflow faults may result if the stack is overloaded.
Lack of Random Access: Unlike arrays or linked lists, stacks do not support random access to their elements. Only the top-most element of the stack can be accessed; to access subsequent components, you must remove elements from the top until you reach the one you want.
Limited Search Capabilities: Stacks need better search features. You would need to pop elements in order to search for them in a stack until you found the one you were looking for or got to the end of the stack.
Stacks are not suitable for complex data structures: Stacks are better suited for simple data structures and instances where the LIFO principle applies. Other data structures might be better appropriate for circumstances needing random access, effective searching, or complex data structures.
Size Limitations: The amount of RAM that can be used usually sets a stack size limit. A stack might not be the best option if the programme needs to handle many items or dynamic resizing.