알고리즘/백준

[백준] 10828번: 스택 (Java) (Stack vs. Deque)

jyunee 2025. 5. 7. 02:44

🔎 스택이란?

스택은 자료를 차곡차곡 쌓아 올리는 구조!

→ 가장 마지막에 넣은 데이터가 제일 먼저 나감 (LIFO: Last In, First Out)

 

🔥 자바에서 스택 사용하는 법

자바에서는 스택을 클래스로 제공합니다.

따라서 해당 라이브러리를 import 해주면 됩니다.

import java.util.Stack;

 

주요 메서드

메서드 이름 설명 예시
push(item) 스택에 아이템을 추가한다. stack.psh(10);
pop() 스택의 맨 위 아이템을 꺼내고 제거한다. int top = stack.pop();
peek() 스택의 맨 위 아이템을 꺼내지만 제거하지 않는다. int top = stack.peek();
isEmpty() 스택이 비어있는지 확인한다. (true of false) stack.isEmpty();
size() 스택 안에 몇 개의 item이 들어있는지 알려준다. stack.size();

 


문제

정수를 저장하는 스택을 구현한 다음, 입력으로 주어지는 명령을 처리하는 프로그램을 작성하시오.

명령은 총 다섯 가지이다.

  • push X: 정수 X를 스택에 넣는 연산이다.
  • pop: 스택에서 가장 위에 있는 정수를 빼고, 그 수를 출력한다. 만약 스택에 들어있는 정수가 없는 경우에는 -1을 출력한다.
  • size: 스택에 들어있는 정수의 개수를 출력한다.
  • empty: 스택이 비어있으면 1, 아니면 0을 출력한다.
  • top: 스택의 가장 위에 있는 정수를 출력한다. 만약 스택에 들어있는 정수가 없는 경우에는 -1을 출력한다.

입력

첫째 줄에 주어지는 명령의 수 N (1 ≤ N ≤ 10,000)이 주어진다. 둘째 줄부터 N개의 줄에는 명령이 하나씩 주어진다. 주어지는 정수는 1보다 크거나 같고, 100,000보다 작거나 같다. 문제에 나와있지 않은 명령이 주어지는 경우는 없다.

출력

출력해야하는 명령이 주어질 때마다, 한 줄에 하나씩 출력한다.


자바 코드

import java.util.Scanner;
import java.util.Stack;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        Stack<Integer> stack = new Stack<>();

        int n = sc.nextInt();
        sc.nextLine(); // 개행 문자 제거

        for (int i = 0; i < n; i++) {
            String command = sc.nextLine();

            if (command.startsWith("push")) {
                int num = Integer.parseInt(command.split(" ")[1]);
                stack.push(num);
            } else if (command.equals("pop")) {
                System.out.println(stack.isEmpty() ? -1 : stack.pop());
            } else if (command.equals("size")) {
                System.out.println(stack.size());
            } else if (command.equals("empty")) {
                System.out.println(stack.isEmpty() ? 1 : 0);
            } else if (command.equals("top")) {
                System.out.println(stack.isEmpty() ? -1 : stack.peek());
            }
        }
    }
}

코드 설명

  1. 키보드로 입력을 받을 수 있도록 Scanner 객체 생성
  2. Stack 타입 변수 생성
    • Stack<Integer> stack = new Stack<>();
    • Integer 타입만 넣을 수 있도록 설정
  3. n 입력받기
    • int n = sc.nextInt();
    • 주의! sc.nextLine() 해줘야 함 → 숫자를 입력받으면 줄 바꿈(’\n’)이 남아 있기 때문에 없애줘야 함 (안 한번 버그)
    • n 번 반복하면서 명령어 하나하나 처리
  4. 명령어 하나씩 처리 (if-else 문 사용)
    • push X
      • push로 시작하는 명령어 찾기
      • 공백 기준으로 자름
      • 숫자 X를 숫자로 바꾼 후,
      • stack.push()를 이용해서 스택에 넣음
    • pop
      • 명령어가 pop인 경우
      • 스택이 비어 있으면 -1 출력
      • 아니면 stack.pop()으로 맨 위 값을 빼내고 출력
    • size
      • 스택에 몇 개가 들어 있는지 stack.size()로 출력
    • empty
      • 스택이 비어 있으면 1 출력
      • 아니면 0 출력
    • top
      • 스택이 비어 있으면 -1 출력
      • 아니면 stack.peek()으로 맨 위 값을 보기만 하고 출력 (빼내지 않음)

✅ Stack 클래스의 내부적 구조

  • 사실 자바의 Stack은 Vector를 상속받아서 만들어집니다.
  • Vector는 크기를 자동으로 늘려주는 동적 배열!
  • 그래서 스택은 내부에서 배열처럼 데이터를 저장하고 있습니다.
  • (원래 스택은 배열로 만들 수도, 연결리스트로 만들 수도 있는데, 자바 기본 Stack은 배열 기반!)

⚠️ Stack 클래스의 단점

Stack 클래스는 오래된 클래스 (Vector 기반이라 좀 느릴 수도 있음)입니다.

그래서 요즘은 ArrayDeque라는 클래스를 더 추천한다고 하네요.

  • 더 빠르고
  • 더 가볍고
  • 최신 버전 최적화가 잘 되어 있음

🔥 ArrayDeque란?

  • 이름 그대로
    • Array → 내부적으로 배열을 사용
    • Deque → “Double Ended Queue” (앞에서도, 뒤에서도 넣고 뺄 수 있음)
  • Stack처럼도 쓸 수 있고, Queue처럼도 쓸 수 있음 (엄청 유연함)
  • 속도도 아주 빠르고 메모리 효율도 좋음

즉, “최신 자바에서는 Stack 대신 ArrayDeque를 쓰자”가 정석!

 

ArrayDeque를 사용한 구현은 다음과 같이 하면 됩니다.

import java.io.*;
import java.util.ArrayDeque;
import java.util.Deque;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));

        Deque<Integer> stack = new ArrayDeque<>();
        int n = Integer.parseInt(reader.readLine());

        for (int i = 0; i < n; i++) {
            String command = reader.readLine();

            if (command.startsWith("push")) {
                int num = Integer.parseInt(command.split(" ")[1]);
                stack.push(num);
            } else if (command.equals("pop")) {
                writer.write(stack.isEmpty() ? "-1" : String.valueOf(stack.pop()));
                writer.newLine();
            } else if (command.equals("size")) {
                writer.write(String.valueOf(stack.size()));
                writer.newLine();
            } else if (command.equals("empty")) {
                writer.write(stack.isEmpty() ? "1" : "0");
                writer.newLine();
            } else if (command.equals("top")) {
                writer.write(stack.isEmpty() ? "-1" : String.valueOf(stack.peek()));
                writer.newLine();
            }
        }

        writer.flush(); // 반드시 출력
    }
}

 

위 코드에서는 Scanner와 System.out.println 대신 BufferedReader와 BufferedWriter를 사용했습니다.

이에 대해 알고 싶다면 아래 포스트 내용을 한 번 읽어 보세요!

 

[백준] 15552번: 빠른 A+B (자바 Java)

Java에서 빠른 입출력 정리자바(Java)에서 입력(Scanner)과 출력(System.out.println)은 편리하지만, 속도가 느리기 때문에 많은 데이터 처리에서는 시간 초과가 발생할 수 있다.→ 그래서 BufferedReader와 Buff

jyun2e.tistory.com


✅ Stack vs. ArrayDeque 비교

항목  Stack  ArrayDeque
기반 구조 Vector (옛날 방식, 동기화됨) 배열 기반 (최신, 빠름)
쓰는 메서드 push, pop, peek push, pop, peek (같음!)
속도 조금 느림 (동기화 때문에) 훨씬 빠름 (비동기화)
추천 여부 ❌ (옛날) ✅ (요즘 다 씀)

 

✅ 왜 ArrayDeque가 좋은 걸까?

  • 스레드 동기화를 하지 않아서 Stack보다 빠름
  • (Stack은 멀티스레드용이라 항상 lock을 잡는데, 보통은 필요 없음)
  • 배열처럼 메모리를 효율적으로 씀
  • 앞뒤로 넣고 뺄 수 있어서 Queue처럼도 쓸 수 있음
  • Stack 메서드(push, pop, peek, size, isEmpty)를 똑같이 제공
    • 하지만 Stack과 달리 Deque는 앞뒤로 넣고 뺄 수 있기 때문에, 위 메서드 말고도 다른 메서드가 추가로 존재합니다.
    • 지금은 스택 구조에 대해서 다루고 있기 때문에 다른 메서드에 관해서는 넘어가도록 하겠습니다!
    • 중요한 것은 Deque를 사용해도 Stack과 동일한 메서드를 사용할 수 있다는 것!

💡 실전 꿀팁

Deque 타입으로 선언하고 ArrayDeque로 생성해라!

왜냐하면, 인터페이스 타입(Deque)으로 코딩하면 더 유연하고 좋습니다.

Deque<Integer> stack = new ArrayDeque<>();

(인터페이스를 사용하면 나중에 다른 구현체로 바꾸기도 쉬움)

 

Deque는 인터페이스이기 때문에 사실 ArrayDeque 말고도 LinkedList를 통해 구현할 수도 있습니다.

하지만 Stack/Queue 용도로는 ArrayDeque가 대부분의 상황에서 더 좋아요

LinkedList는 중간 삽입/삭제가 필요한 경우에만 고려하는 게 좋습니다.


📌 정리 한 줄

“ArrayDeque는 빠르고 좋은 현대식 스택이다! push, pop, peek 메서드를 쓰면 Stack처럼 완벽하게 동작한다!”