Lesson 1
Introduction to Stacks in Ruby
Introduction

Greetings! Today, we're unveiling the concept of Stacks in Ruby, a fundamental data structure. Imagine a stack as 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. Ruby handles stacks effortlessly with Arrays. This lesson will illuminate the stack data structure, operations, and their Ruby applications. Are you ready to start?

Understanding Stack: A Data Structure on the Rise

A stack is a storage structure that allows Push (addition) and Pop (removal) operations. It's akin to a stack of plates in a cafeteria, where plates are added (pushed) and removed (popped) from the top. No plate can be taken from the middle or the bottom, exemplifying a Last-In, First-Out (LIFO) operation.

Utilizing Arrays as Stacks in Ruby

To create a stack, Ruby employs a built-in data structure known as an Array. For the Push operation, we use push, which adds an element at the end of the array. For the Pop operation, there's the pop method that removes the last element, simulating the removal of the 'top' element in a stack. Here's how it looks:

Ruby
1stack = [] # A new empty stack 2 3# Push operations 4stack.push('John') 5stack.push('Mary') 6stack.push('Steve') 7 8stack.pop # Pop operation removes 'Steve' 9puts stack.inspect # Outputs: ["John", "Mary"]

In the example provided, we push 'John', 'Mary', and 'Steve' into the stack and then pop 'Steve' from the stack.

Advanced Stack Operations

Stack operations go beyond merely push and pop. For example, to verify if a stack is empty, you can use the empty? method. If it returns true, that means the stack is empty. Conversely, if it returns false, we can infer the stack is not empty. To peek at the top element of the stack without popping it, indexing with -1 is handy.

Here's an example:

Ruby
1stack.push('Sam') 2puts stack.last # Outputs: 'Sam'

In this example, 'Sam' is added (pushed), and then the topmost stack element, which is 'Sam', is peeked.

Practical Stack Applications: Reversing a String

Practical applications of stacks in Ruby 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!

Ruby
1def reverse_string(input_string) 2 stack = input_string.chars 3 4 reversed_string = '' 5 until stack.empty? 6 reversed_string += stack.pop 7 end 8 reversed_string 9end 10 11puts reverse_string('HELLO') # Outputs: OLLEH
Practical Stack Applications: Checking Balance of Parentheses

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 the strings "([]()", ")()[]{}", "([)]", and "[{})" they are not.

Let's break down the solution into simple steps:

We start by creating a hash that maps each closing bracket to its corresponding opening bracket and an empty stack. Then, we iterate over each character paren in the string paren_string:

  • 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.

Ruby
1def is_paren_balanced(paren_string) 2 stack = [] 3 is_balanced = true 4 index = 0 5 opening_paren = {')' => '(', ']' => '[', '}' => '{'} # a matching opening parenthesis for every closing one 6 7 # Traversing all string characters 8 while index < paren_string.length && is_balanced 9 paren = paren_string[index] 10 if "([{".include?(paren) 11 # We met an opening parenthesis, just putting it on stack 12 stack.push(paren) 13 else 14 # We met a closing parenthesis 15 if stack.empty? 16 # The parenthesis is closing, but there are no items in the stack 17 is_balanced = false 18 else 19 if stack.last != opening_paren[paren] 20 # The parenthesis on top of the stack doesn't match 21 is_balanced = false 22 else 23 stack.pop 24 end 25 end 26 end 27 index += 1 28 end 29 30 if !stack.empty? 31 # If after traversing all characters, there is something left, it's bad 32 is_balanced = false 33 end 34 is_balanced 35end 36 37puts is_paren_balanced("(())") # Outputs: true 38puts is_paren_balanced("({[)}") # Outputs: false
Lesson Summary and Steps Ahead

Great job! Having covered the stack data structure, operations, and their Ruby applications 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 Ruby!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.