데이터를 어떤 순서로 꺼낼지만 다를 뿐인데, 쓰임새가 완전히 갈려요. 맨 위에서만 꺼내는 스택(LIFO)과 줄 선 순서대로 꺼내는 큐(FIFO), 이 둘의 감을 확실히 잡아봐요.
push·pop·enqueue·dequeue가 각각 무엇을 하는지 알아요.스택(Stack)은 LIFO(Last In First Out, 후입선출) 방식이에요. 마지막에 넣은 것이 가장 먼저 나와요. 접시를 쌓을 때처럼, 맨 위에서만 새로 올리고(push) 맨 위 것부터 내려요(pop).
push(3) pop() → 3
┌───┐ ┌───┐
│ 3 │ ←맨위 │ │
├───┤ ├───┤
│ 2 │ │ 2 │ ←이제 맨위
├───┤ ├───┤
│ 1 │ │ 1 │
└───┘ └───┘
💡 넣고 빼는 곳이 한 곳(맨 위)뿐이라는 게 핵심이에요. 그래서 마지막에 넣은 게 제일 먼저 나오는 거예요.
| 연산 | 하는 일 | 복잡도 |
|---|---|---|
push(x) | 맨 위에 x를 올린다 | O(1) |
pop() | 맨 위 것을 꺼내 없앤다 (그 값을 반환) | O(1) |
peek() | 맨 위 것을 보기만 한다 (빼지 않음) | O(1) |
스택은 "가장 최근 것부터 되짚어야 하는" 상황에서 힘을 발휘해요. 대표적인 쓰임새를 볼게요.
| 활용 | 왜 스택인가 |
|---|---|
| 괄호 짝 검사 | 여는 괄호를 push하고, 닫는 괄호가 오면 pop해서 짝이 맞는지 확인 |
| 실행 취소(undo) | 가장 최근 작업부터 되돌려야 하므로 마지막에 쌓인 것부터 꺼냄 |
| 함수 호출 스택 | 가장 나중에 호출된 함수가 먼저 끝나고 반환됨 (call stack) |
| 브라우저 뒤로가기 | 방문한 페이지를 쌓아두고, 뒤로가기 시 가장 최근 페이지부터 되돌아감 |
const stack = [];
stack.push(1); // [1]
stack.push(2); // [1, 2]
stack.push(3); // [1, 2, 3]
const top = stack.pop(); // 3 을 꺼냄 → stack은 [1, 2]
console.log(top); // 3 (마지막에 넣은 것!)
console.log(stack[stack.length - 1]); // 2 ← peek (보기만)
💡 pop()은 맨 뒤(=맨 위) 요소를 꺼내 없애고 그 값을 돌려줘요. 위 코드에서 마지막에 넣은 3이 가장 먼저 나오죠.
큐(Queue)는 FIFO(First In First Out, 선입선출) 방식이에요. 먼저 넣은 것이 먼저 나와요. 줄서기처럼 뒤로 들어와서(enqueue) 앞에서 빠져나가요(dequeue).
enqueue → [ 1 ][ 2 ][ 3 ] → dequeue
(뒤로 넣음) (앞에서 뺌)
dequeue() → 1 (가장 먼저 들어온 것!)
남은 큐: [ 2 ][ 3 ]
💡 스택은 넣고 빼는 곳이 같은 쪽, 큐는 넣는 곳(뒤)과 빼는 곳(앞)이 반대쪽이에요. 그래서 순서가 그대로 유지돼요.
| 연산 | 하는 일 |
|---|---|
enqueue(x) | 뒤에 x를 넣는다 |
dequeue() | 앞에서 하나 꺼낸다 (가장 먼저 들어온 것) |
큐는 "먼저 온 것을 먼저 처리한다"는 공정한 순서가 필요한 곳에 쓰여요.
| 활용 | 왜 큐인가 |
|---|---|
| 작업 대기열 | 프린터·요청 처리 등, 들어온 순서대로 하나씩 처리해야 공정해요 |
| 너비 우선 탐색(BFS) | 가까운 곳부터 먼저 발견한 순서대로 방문하려면 큐가 필수예요 |
| 버퍼·스트리밍 | 먼저 도착한 데이터부터 순서대로 소비해요 |
JS의 배열은 push·pop·shift를 다 가지고 있어서, 빼는 위치만 바꾸면 스택도 큐도 만들 수 있어요.
const stack = [];
stack.push('a'); // ['a']
stack.push('b'); // ['a', 'b']
stack.pop(); // 'b' 를 꺼냄 (맨 뒤) → LIFO
뒤에 넣고 뒤에서 빼요 → 마지막에 넣은 게 먼저 나옴.
const queue = [];
queue.push('a'); // ['a']
queue.push('b'); // ['a', 'b']
queue.shift(); // 'a' 를 꺼냄 (맨 앞) → FIFO
뒤에 넣고 앞에서 빼요 → 먼저 넣은 게 먼저 나옴.
💡 shift()는 맨 앞 요소를 꺼내요. 다만 앞을 빼면 뒤 요소를 다 당겨야 해서 O(n)이에요. 진짜 대량 처리에선 별도 큐 구조를 쓰지만, 코테 감 잡기엔 배열로 충분해요.
| 스택 (Stack) | 큐 (Queue) | |
|---|---|---|
| 순서 | LIFO · 후입선출 | FIFO · 선입선출 |
| 비유 | 접시 쌓기 | 줄서기 |
| 넣기 | push (맨 위/뒤) | enqueue (뒤) |
| 빼기 | pop (맨 위/뒤) | dequeue (앞) |
| JS 배열 | push / pop | push / shift |
| 대표 쓰임 | undo·괄호검사·호출스택 | BFS·대기열·버퍼 |
push·pop, 마지막에 넣은 게 먼저 나와요.enqueue, 앞에서 dequeue, 먼저 넣은 게 먼저 나와요.push/pop, 큐는 push/shift. 빼는 위치만 다르면 돼요.