스택은 컴퓨터 과학에서 매우 기본적이면서도 중요한 자료 구조 중 하나이다. 백준 온라인 저지의 10828번 문제는 이러한 스택의 구현과 관련된 문제로, 다양한 명령을 효율적으로 처리해야 한다. 이번 글에서는 이 문제를 상세히 분석하고, C++과 Python으로 구현하는 방법을 소개한다.
문제 : https://www.acmicpc.net/problem/10828
문제 설명
백준 10828번 문제는 정수를 저장할 수 있는 스택을 구현하고, 주어진 명령을 처리하는 프로그램을 작성하는 것이다. 스택은 LIFO(Last In, First Out) 구조로, 가장 나중에 삽입된 요소가 먼저 제거되는 특성을 가진다. 문제에서 요구하는 명령은 총 다섯 가지로, push X
, pop
, size
, empty
, top
이 있다.
push X
: 정수 X를 스택에 넣는 연산이다.pop
: 스택에서 가장 위에 있는 정수를 빼고, 그 수를 출력한다. 스택이 비어있으면 -1을 출력한다.size
: 스택에 들어있는 정수의 개수를 출력한다.empty
: 스택이 비어있으면 1, 아니면 0을 출력한다.top
: 스택의 가장 위에 있는 정수를 출력한다. 스택이 비어있으면 -1을 출력한다.
입력으로는 첫 번째 줄에 명령의 수 N(1 ≤ N ≤ 10,000)이 주어지고, 그 다음 N개의 줄에 각 명령이 주어진다. 출력은 각 명령에 대해 요구되는 결과를 한 줄씩 출력하면 된다.
예를 들어, 다음과 같은 입력이 주어졌을 때:
|
|
출력은 다음과 같이 된다:
|
|
접근 방식
이 문제는 기본적인 스택 자료 구조의 구현과 명령 처리를 요구한다. 스택을 구현하는 방법은 여러 가지가 있지만, C++에서는 std::vector
를 이용하거나 직접 배열을 관리할 수 있다. Python에서는 리스트를 사용하여 스택을 쉽게 구현할 수 있다.
효율적인 입출력이 중요하다. 특히, C++에서는 std::cin
과 std::cout
의 동기화를 해제하고, std::cin.tie(NULL)
을 사용하여 입출력 속도를 향상시킬 수 있다. 이는 큰 입력을 처리할 때 시간 초과를 방지하는 데 도움이 된다.
명령을 처리할 때는 각 명령을 빠르게 파싱하고, 스택의 상태를 정확하게 관리해야 한다. push
명령의 경우 추가적인 정수 X를 입력받아 스택에 삽입하고, 나머지 명령들은 스택의 현재 상태를 기반으로 결과를 출력하면 된다.
C++ 코드와 설명
|
|
코드의 동작 단계별 설명
입출력 속도 향상:
1 2
std::ios::sync_with_stdio(false); std::cin.tie(NULL);
std::ios::sync_with_stdio(false);
는 C++의 표준 입출력과 C의 표준 입출력 간의 동기화를 해제하여 입출력 속도를 향상시킨다.std::cin.tie(NULL);
는cin
과cout
의 묶음을 풀어,cin
이cout
을 자동으로 flush하지 않도록 한다.
스택 구현:
1
std::vector<int> stack;
std::vector
를 사용하여 스택을 구현하였다.push_back
과pop_back
메서드를 통해 스택의push
와pop
연산을 수행한다.
명령 처리:
1 2 3 4
for(int i = 0; i < N; ++i){ std::cin >> command; // 명령어에 따라 분기 처리 }
- 입력으로 주어진 N개의 명령을 하나씩 처리한다. 각 명령어에 따라 적절한 연산을 수행하고, 결과를 출력한다.
각 명령어에 대한 처리:
- push X: 스택에 X를 삽입한다.
- pop: 스택의 가장 위 요소를 출력하고 제거한다. 스택이 비어있으면 -1을 출력한다.
- size: 스택의 크기를 출력한다.
- empty: 스택이 비어있으면 1, 아니면 0을 출력한다.
- top: 스택의 가장 위 요소를 출력한다. 스택이 비어있으면 -1을 출력한다.
C++ without library 코드와 설명
|
|
코드의 동작 단계별 설명
스택 구조체 정의:
1 2 3 4 5 6
struct Stack { int* arr; int top; int capacity; // 생성자와 메서드 정의 };
- 스택을 배열로 구현하기 위해 구조체를 정의하였다.
arr
는 스택을 저장할 배열,top
은 현재 스택의 최상위 인덱스,capacity
는 스택의 최대 크기를 나타낸다.
- 스택을 배열로 구현하기 위해 구조체를 정의하였다.
스택 초기화 및 메서드 구현:
1 2 3 4 5
Stack(int size) { arr = (int*)malloc(sizeof(int) * size); top = -1; capacity = size; }
- 생성자에서 스택의 배열을 동적으로 할당하고,
top
을 -1로 초기화하여 스택이 비어있음을 나타낸다.
1 2 3 4 5
void push(int x) { /* ... */ } int pop() { /* ... */ } int size() { /* ... */ } int empty() { /* ... */ } int getTop() { /* ... */ }
- 각 메서드는
push
,pop
,size
,empty
,top
명령을 처리하기 위한 기능을 제공한다.
- 생성자에서 스택의 배열을 동적으로 할당하고,
명령 처리:
1 2 3 4
for(int i = 0; i < N; ++i){ std::cin >> command; // 명령어에 따라 스택의 메서드를 호출 }
- 입력으로 주어진 N개의 명령을 하나씩 읽어들여, 해당 명령에 맞는 스택의 메서드를 호출하여 처리한다.
메모리 관리:
1
free(stack.arr);
- 동적으로 할당한 메모리를 프로그램 종료 전에 해제하여 메모리 누수를 방지한다.
Python 코드와 설명
|
|
코드의 동작 단계별 설명
입출력 최적화:
1 2 3
import sys input = sys.stdin.read data = input().split()
sys.stdin.read
를 사용하여 모든 입력을 한 번에 읽어들이고, 이를 공백으로 분리하여 리스트data
에 저장한다. 이는 입력이 많을 때 효율적이다.
스택 구현:
1
stack = []
- Python의 리스트를 이용하여 스택을 구현하였다.
append
와pop
메서드를 통해 스택의push
와pop
연산을 수행한다.
- Python의 리스트를 이용하여 스택을 구현하였다.
명령 처리:
1 2 3
for _ in range(N): command = data[idx] # 명령어에 따라 스택 연산 수행
- 리스트
data
를 순회하면서 각 명령어를 처리한다.push
명령의 경우 추가로 정수 X를 읽어와 스택에 삽입한다. 나머지 명령들은 스택의 현재 상태에 따라 결과를 리스트output
에 저장한다.
- 리스트
출력:
1
print('\n'.join(output))
- 결과를 리스트
output
에 저장한 후, 한 번에 출력하여 시간 효율을 높인다.
- 결과를 리스트
결론
백준 10828번 문제는 기본적인 스택 자료 구조의 구현과 효율적인 명령 처리를 요구한다. C++과 Python 모두에서 스택을 효과적으로 구현할 수 있으며, 특히 입출력 최적화를 통해 시간 제한을 만족시킬 수 있다. C++에서는 std::vector
를 사용하여 간편하게 스택을 구현할 수 있으며, Python에서는 리스트를 활용하여 동일한 기능을 수행할 수 있다.
추가적으로, C++에서 표준 라이브러리를 사용하지 않고 스택을 구현함으로써 메모리 관리의 중요성을 체감할 수 있었다. 이러한 문제를 통해 자료 구조의 기본 원리를 이해하고, 효율적인 알고리즘 설계의 필요성을 다시 한 번 느낄 수 있었다. 앞으로 더 복잡한 자료 구조와 알고리즘 문제를 풀 때에도 이러한 기본기를 바탕으로 문제를 접근하면 보다 효율적으로 해결할 수 있을 것이다.