# Stacks

A stack is a fundamental data structure that follows the Last In, First Out (LIFO) principle. This means that the last element added to the stack will be the first one to be removed. Stacks are widely used in programming and computing for various tasks such as function call management, expression evaluation, and undo mechanisms in software applications.

The analogy often used to describe a stack is a stack of plates; you can only add or remove the top plate, and the last plate you put on top is the first one you'll take off. Similarly, in a stack data structure, elements are added (pushed) and removed (popped) from the top of the stack.

The basic operations associated with stacks include:

* **Push:** Add an element to the top of the stack.
* **Pop:** Remove the top element from the stack and return it.
* **Peek/Top:** View the top element of the stack without removing it, providing insight into the most recently added element.
* **IsEmpty:** Check if the stack is empty, indicating whether there are any elements to pop or peek at.
* **IsFull:** Check if the stack is full (relevant in the context of stacks with a fixed size).

Stacks can be implemented using various underlying data structures, such as linked lists or arrays. The implementation choice affects the complexity, efficiency, and capabilities of the stack operations.

Stacks play a crucial role in several computer science and programming concepts, including:

* **Function Calls/Recursion:** Stacks manage the order in which functions are called and returned in programming languages. Each function call adds a new frame to the stack (push), and when the function returns, its frame is removed (pop). This is also how recursive functions work.
* **Expression Evaluation:** Stacks are used to evaluate postfix or prefix expressions and to convert infix expressions to postfix or prefix.
* **Undo Mechanism:** Many applications use stacks to keep track of operations or changes, allowing users to undo actions by popping the last operation from the stack and reversing it.

The simplicity and effectiveness of the LIFO principle make stacks an essential data structure in computer science and software development, facilitating the management of data in a controlled, last-in-first-out manner.

Below is a simple example of implementing a stack in Python using a list. This example will demonstrate the basic stack operations: push (to add an item to the top of the stack), pop (to remove the top item from the stack), and peek (to view the top item without removing it).

```python
class Stack:
    def __init__(self):
        self.items = []  # Initialize an empty list to use as the stack

    def is_empty(self):
        """Check if the stack is empty."""
        return not self.items

    def push(self, item):
        """Add an item to the top of the stack."""
        self.items.append(item)

    def pop(self):
        """Remove and return the top item from the stack. Assumes the stack is not empty."""
        if not self.is_empty():
            return self.items.pop()
        else:
            return "Stack is empty"

    def peek(self):
        """Return the top item from the stack without removing it. Assumes the stack is not empty."""
        if not self.is_empty():
            return self.items[-1]
        else:
            return "Stack is empty"

    def size(self):
        """Return the number of items in the stack."""
        return len(self.items)

# Create a stack instance
stack = Stack()

# Push items onto the stack
stack.push("A")
stack.push("B")
stack.push("C")

# Peek at the top item
print(f"Top item is: {stack.peek()}")

# Pop an item off the stack
print(f"Popped item: {stack.pop()}")

# Check the current size of the stack
print(f"Stack size after popping: {stack.size()}")
```

In this code, the `Stack` class encapsulates the operations and properties of a stack. We use a Python list to store the elements of the stack, where the end of the list represents the top of the stack. This allows us to use the list's append and pop methods to implement the stack's push and pop operations, respectively. The `peek` method simply returns the last item in the list (the top of the stack) without removing it, and `is_empty` checks if the stack is empty by verifying if the list is empty.
