IT이야기/보안

스택(Stack): 후입선출(LIFO) 구조의 개념과 활용

Chiba-in 2025. 3. 1. 19:15

🔹 스택이란?

1. 스택(Stack)의 정의

스택(Stack)후입선출(LIFO, Last In First Out) 원칙을 따르는 선형 데이터 구조로, 마지막에 추가된 요소가 가장 먼저 제거되는 구조입니다. 스택은 메모리 관리, 함수 호출, 괄호 검사, 되돌리기(Undo) 기능 등 다양한 컴퓨터 과학 분야에서 활용됩니다.

스택의 주요 특징:

  • 후입선출(LIFO) 방식으로 작동
  • 삽입(push)과 삭제(pop) 연산만 수행 가능
  • 항상 가장 최근에 추가된 요소를 제거
  • O(1)의 시간 복잡도로 연산 수행 가능

📌 스택은 후입선출 구조를 활용하는 알고리즘과 시스템에서 필수적인 데이터 구조입니다.


🔹 스택의 주요 연산

1. 삽입(Push) - O(1)

새로운 요소를 스택의 맨 위에 추가하는 연산

✔️ Push 연산 예제 (Python):

stack = []
stack.append(10)  # 10 추가
stack.append(20)  # 20 추가
print(stack)  # 출력: [10, 20]

📌 스택의 삽입 연산은 O(1) 시간 복잡도를 가집니다.

2. 삭제(Pop) - O(1)

스택의 맨 위에 있는 요소를 제거하고 반환하는 연산

✔️ Pop 연산 예제 (Python):

stack = [10, 20, 30]
print(stack.pop())  # 출력: 30
print(stack)  # 출력: [10, 20]

📌 가장 최근에 추가된 요소를 제거하는 것이 스택의 핵심 개념입니다.

3. 조회(Peek) - O(1)

스택의 맨 위에 있는 요소를 제거하지 않고 조회하는 연산

✔️ Peek 연산 예제 (Python):

stack = [10, 20, 30]
print(stack[-1])  # 출력: 30 (가장 위의 요소)

📌 스택의 맨 위 요소를 확인할 수 있지만, 제거되지는 않습니다.

4. 스택이 비어있는지 확인(Is Empty) - O(1)

스택이 비어있는지 확인하는 연산

✔️ Is Empty 연산 예제 (Python):

stack = []
print(len(stack) == 0)  # 출력: True

📌 비어있는지 확인하는 것은 프로그램의 오류 방지에 유용합니다.


🔹 스택의 구현 방법

1. 리스트(List)를 이용한 스택 구현 (Python)

Python의 리스트를 활용한 기본적인 스택 구현

✔️ 리스트 기반 스택 예제:

class Stack:
    def __init__(self):
        self.stack = []

    def push(self, item):
        self.stack.append(item)

    def pop(self):
        if not self.is_empty():
            return self.stack.pop()
        return "Stack is empty"

    def peek(self):
        if not self.is_empty():
            return self.stack[-1]
        return "Stack is empty"

    def is_empty(self):
        return len(self.stack) == 0

    def size(self):
        return len(self.stack)

s = Stack()
s.push(10)
s.push(20)
print(s.pop())  # 출력: 20
print(s.peek())  # 출력: 10

📌 Python의 리스트는 동적 배열이므로 스택으로 쉽게 활용할 수 있습니다.

2. 연결 리스트(Linked List)를 이용한 스택 구현

연결 리스트를 활용한 스택 구현은 메모리를 효율적으로 사용할 수 있음

✔️ 연결 리스트 기반 스택 예제:

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

class LinkedListStack:
    def __init__(self):
        self.top = None

    def push(self, data):
        new_node = Node(data)
        new_node.next = self.top
        self.top = new_node

    def pop(self):
        if self.is_empty():
            return "Stack is empty"
        popped_data = self.top.data
        self.top = self.top.next
        return popped_data

    def peek(self):
        return self.top.data if self.top else "Stack is empty"

    def is_empty(self):
        return self.top is None

s = LinkedListStack()
s.push(10)
s.push(20)
print(s.pop())  # 출력: 20
print(s.peek())  # 출력: 10

📌 연결 리스트를 사용하면 스택의 크기가 동적으로 조정됩니다.


🔹 스택의 활용 사례

1. 괄호 검사(Parenthesis Matching)

코드에서 괄호가 올바르게 닫혔는지 확인하는 데 사용

✔️ 괄호 검사 예제:

def is_balanced(expression):
    stack = []
    for char in expression:
        if char in "({[":
            stack.append(char)
        elif char in ")}]":
            if not stack:
                return False
            top = stack.pop()
            if (top == "(" and char != ")") or (top == "{" and char != "}") or (top == "[" and char != "]"):
                return False
    return len(stack) == 0

print(is_balanced("{[()]}"))  # 출력: True
print(is_balanced("{[(])}"))  # 출력: False

📌 스택을 사용하면 괄호의 짝을 쉽게 검사할 수 있습니다.

2. 함수 호출 스택(Call Stack)

재귀 함수 호출이 이루어지는 방식

✔️ 재귀 함수 호출 예제:

def factorial(n):
    if n == 0:
        return 1
    return n * factorial(n - 1)

print(factorial(5))  # 출력: 120

📌 재귀 함수는 내부적으로 스택을 사용하여 호출을 관리합니다.


📌 결론

스택(Stack)은 후입선출(LIFO) 원칙을 따르는 선형 데이터 구조입니다.
삽입(push)과 삭제(pop)은 O(1)의 시간 복잡도를 가집니다.
괄호 검사, 함수 호출 스택, 되돌리기(Undo) 기능 등 다양한 분야에서 활용됩니다.
배열 또는 연결 리스트를 이용하여 스택을 구현할 수 있습니다.