(CS/컴퓨터공학) 스택·큐·덱(Deque) 개념 및 비교

✨ 개요

스택·큐·덱(Deque) 개념 및 비교 — 연산, 복잡도, 언제 무엇을 쓸까

스택(Stack), 큐(Queue), 덱(Deque)은 순서가 있는 선형 자료구조의 기본 형태입니다.
실무에서는 컬렉션 선택만 잘해도 성능과 코드 단순성이 크게 개선됩니다.


1. 한 장 요약

구조 핵심 개념 출입 방향 주요 연산 시간복잡도(배열/덱 기반) 대표 구현
스택 마지막에 넣은 것을 먼저 꺼냄 (LIFO) 한쪽 push, pop, peek, isEmpty 평균 O(1) ArrayDeque(권장), Stack(구식)
먼저 넣은 것을 먼저 꺼냄 (FIFO) 양쪽(뒤로 넣고 앞에서 뺌) offer/add, poll/remove, peek 평균 O(1) ArrayDeque, LinkedList(권장 X)
양 끝에서 넣고 빼기(Double-Ended Queue) 양쪽 addFirst/Last, pollFirst/Last, peekFirst/Last 평균 O(1) ArrayDeque

JVM/코틀린에서는 ArrayDeque 가 스택/큐/덱 용도로 가장 빠르고 메모리 효율이 좋습니다.


2 개념 그림(ASCII)

스택 (LIFO)

push → [ a | b | c(top) ]
pop ← ^ (c가 먼저 나옴)

2.2 큐 (Queue)

offer → [ a | b | c ] → poll
^front ^back

2.3 덱 (Double-Ended)

addFirst → [ x | a | b | c ] ← addLast
pollFirst ← → pollLast

3 언제 무엇을 쓰나?


4. 코틀린 사용 예제 (JVM 표준 라이브러리 기반)

4.1 스택: 괄호 유효성 검사

fun isValidBrackets(s: String): Boolean {
    val stack = ArrayDeque<Char>() // 스택으로 사용
    val pair = mapOf(')' to '(', ']' to '[', '}' to '{')
    for (ch in s) {
        when (ch) {
            '(', '[', '{' -> stack.addLast(ch)              // push
            ')', ']', '}' -> if (stack.isEmpty() || stack.removeLast() != pair[ch]) return false // pop
        }
    }
    return stack.isEmpty()
}

4.2 큐: BFS(최단거리/레벨 순회)

data class Node(val id: Int, val next: List<Int>)

fun bfs(start: Int, graph: Map<Int, Node>): List<Int> {
    val q = ArrayDeque<Int>() // 큐로 사용
    val visited = BooleanArray(graph.size)
    val order = mutableListOf<Int>()
    q.addLast(start); visited[start] = true

    while (q.isNotEmpty()) {
        val cur = q.removeFirst() // poll
        order += cur
        for (n in graph[cur]!!.next) {
            if (!visited[n]) { visited[n] = true; q.addLast(n) } // offer
        }
    }
    return order
}

4.3 덱: 슬라이딩 윈도우 최대값(O(n), 모노토닉 큐)

fun maxSlidingWindow(nums: IntArray, k: Int): IntArray {
    val dq = ArrayDeque<Int>() // 인덱스를 저장, 값은 단조 내림 유지
    val res = IntArray(nums.size - k + 1)
    for (i in nums.indices) {
        // 윈도 범위 밖 제거
        if (dq.isNotEmpty() && dq.first() == i - k) dq.removeFirst()
        // 뒤에서부터 현재 값보다 작은 요소 제거 (단조성 유지)
        while (dq.isNotEmpty() && nums[dq.last()] <= nums[i]) dq.removeLast()
        dq.addLast(i)
        if (i >= k - 1) res[i - k + 1] = nums[dq.first()]
    }
    return res
}


5. 복잡도와 상수 시간의 함정


6. 스택/큐/덱 선택 가이드 (실무 기준)


7. 흔한 실수/오해


8. 요약 체크리스트


결론



Related Posts