Greetings, Space Explorer! Today, we're drawing back the curtains on Stacks in C#, a crucial data structure. A stack
is like a pile of dishes: you add a dish to the top (Last In) and take it from the top (First Out). This Last-In, First-Out (LIFO) principle exemplifies the stack. C# executes stacks effortlessly using the Stack
class from the System.Collections.Generic
namespace. This lesson will illuminate the stack
data structure, its operations, and its applications in C#. Are you ready to start?
To create a stack, C# employs a built-in data structure known as a Stack
. For the push operation, we use Push()
, which adds an element to the stack's end. For the pop operation, there's the Pop()
function that removes the last element, simulating the removal of the 'top' element in a stack. Here's how it looks:
C#1using System; 2using System.Collections.Generic; 3 4public class StackExample 5{ 6 public static void Main(string[] args) 7 { 8 Stack<string> stack = new Stack<string>(); // A new empty stack 9 10 // Push operations 11 stack.Push("John"); 12 stack.Push("Mary"); 13 stack.Push("Steve"); 14 15 stack.Pop(); // Pop operation removes 'Steve' 16 Console.WriteLine(string.Join(" -> ", stack)); // Outputs: John -> Mary 17 } 18}
In the example provided, we push John
, Mary
, and Steve
into the stack and then pop Steve
from the stack.
Stack operations go beyond merely Push
and Pop
. For example, to verify if a stack is empty, we can check if the Count
property is 0
. If it is, that means the stack is empty. To peek at the top element of the stack without popping it, we use the Peek()
method.
Here's an example:
C#1using System; 2using System.Collections.Generic; 3 4public class StackOperations 5{ 6 public static void Main(string[] args) 7 { 8 Stack<string> stack = new Stack<string>(); 9 stack.Push("Steve"); 10 stack.Push("Sam"); 11 12 Console.WriteLine(stack.Peek()); // Outputs: 'Sam' 13 14 Console.WriteLine(stack.Count == 0); // Outputs: False 15 stack.Pop(); // Remove 'Sam' 16 stack.Pop(); // Remove 'Steve' 17 Console.WriteLine(stack.Count == 0); // Outputs: True 18 } 19}
In this example, Sam
is added (pushed
), and then the topmost stack element, which is Sam
, is peeked at.
Practical applications of stacks in C# are plentiful. Here is one of them — reversing a string.
We will push all characters into a stack and then pop them out to get a reversed string!
C#1using System; 2using System.Collections.Generic; 3using System.Text; 4 5public class ReverseString 6{ 7 public static string Reverse(string input) 8 { 9 Stack<char> stack = new Stack<char>(); 10 11 foreach (char c in input) 12 { 13 stack.Push(c); 14 } 15 16 StringBuilder reversedString = new StringBuilder(); 17 while (stack.Count > 0) 18 { 19 reversedString.Append(stack.Pop()); 20 } 21 22 return reversedString.ToString(); 23 } 24 25 public static void Main(string[] args) 26 { 27 Console.WriteLine(Reverse("HELLO")); // Outputs: OLLEH 28 } 29}
A stack can be utilized to verify if parentheses in an expression are well-matched, i.e., every bracket has a corresponding pair. For example, parentheses in the string "()[{}]"
are well-matched, while in strings "([]()"
, ")()[]{}"
, "([)]"
, and "[{})"
they are not.
Let's break down the solution into simple steps:
We start by creating a Dictionary
that maps each closing bracket to its corresponding opening bracket and an empty stack
. Then, we iterate over each character paren
in the string parenString
:
- If
paren
is an opening bracket, it gets appended to the stack. - If
paren
is a closing bracket and the top element in the stack is the corresponding opening bracket, we remove the top element from the stack. - If neither of the above conditions is met, we return
false
.
Finally, if the stack is empty (all opening brackets had matching closing brackets), we return true
. If there are some unmatched opening brackets left, we return false
.
C#1using System; 2using System.Collections.Generic; 3 4public class ParenthesesBalance 5{ 6 public static bool IsParenBalanced(string parenString) 7 { 8 Stack<char> stack = new Stack<char>(); 9 Dictionary<char, char> openingParen = new Dictionary<char, char> 10 { 11 { ')', '(' }, 12 { ']', '[' }, 13 { '}', '{' } 14 }; 15 16 foreach (char paren in parenString) 17 { 18 if (openingParen.ContainsValue(paren)) 19 { 20 // We met an opening parenthesis, just putting it on the stack 21 stack.Push(paren); 22 } 23 else if (openingParen.ContainsKey(paren)) 24 { 25 // We met a closing parenthesis 26 if (stack.Count == 0 || stack.Pop() != openingParen[paren]) 27 { 28 return false; 29 } 30 } 31 } 32 33 return stack.Count == 0; 34 } 35 36 public static void Main(string[] args) 37 { 38 Console.WriteLine(IsParenBalanced("(())")); // Outputs: True 39 Console.WriteLine(IsParenBalanced("({[)}")); // Outputs: False 40 } 41}
Kudos to you! Covering the stack
data structure, its operations, and their applications in C# is a commendable feat. Next up, you'll encounter practice exercises that will solidify your newly acquired knowledge. Dive into them and master Stacks
in C#!