Home 우선순위 큐 Priority Queue
Post
X

우선순위 큐 Priority Queue

우선순위 큐 (Priority Queue)

우선순위 큐는 들어온 순서(FIFO)가 아니라 우선순위가 가장 높은 요소가 먼저 나오는 큐 자료구조입니다.

priority-queue


우선순위 큐의 추상 자료형 ADT

  • push(x) : 우선순위를 가진 요소 삽입
  • pop() : 가장 높은 우선순위 요소 제거 및 반환
  • peek() : 가장 높은 우선순위 요소 조회
  • size() : 요소 갯수 반환

Min Heap

  • 부모 노드 ≤ 자식 노드
  • 루트 노드에 최소값이 위치
  • 최소값을 O(1) 에 조회
  • 삽입 / 삭제는 O(log N)
1
2
3
4
5
        1
      /   \
     3     5
    / \
   8   10

Max Heap

  • 부모 노드 ≥ 자식 노드
  • 루트 노드에 최대값 위치
  • 구현은 Min Heap과 동일하되 비교 연산만 반대
1
2
3
4
5
       10
      /  \
     8    5
    / \
   1   3

구현 코드

대표적인 우선순위 큐의 자료구조 중 하나인 Min Heap을 구현해보겠습니다.

배열로 구현 시 매 삽입/삭제마다 정렬이 필요하여 O(N log N)
힙 기반 구현은 삽입/삭제가 O(log N)
실전에서는 Heap 기반 구현이 표준


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
class MinHeap {
  #heap;

  constructor() {
    this.#heap = [];
  }

  push(x) {
    this.#heap.push(x);
    this._bubbleUp();
  }

  pop() {
    if (this.size() === 0) throw new Error("MinHeap is Empty");
    if (this.size() === 1) return this.#heap.pop();

    let root = this.peek();

    this.#heap[0] = this.#heap.pop();
    this._bubbleDown();

    return root;
  }

  peek() {
    return this.#heap[0];
  }

  size() {
    return this.#heap.length;
  }

  _bubbleUp() {
    let idx = this.size() - 1;

    while (idx > 0) {
      let parentIdx = Math.floor((idx - 1) / 2);

      if (this.#heap[parentIdx] <= this.#heap[idx]) break;

      [this.#heap[parentIdx], this.#heap[idx]] = [
        this.#heap[idx],
        this.#heap[parentIdx],
      ];

      idx = parentIdx;
    }
  }

  _bubbleDown() {
    let idx = 0;
    let len = this.size();

    while (true) {
      let left = idx * 2 + 1,
        right = idx * 2 + 2,
        small = idx;

      if (left < len && this.#heap[small] > this.#heap[left]) small = left;
      if (right < len && this.#heap[small] > this.#heap[right]) small = right;
      if (small === idx) break;

      [this.#heap[small], this.#heap[idx]] = [
        this.#heap[idx],
        this.#heap[small],
      ];

      idx = small;
    }
  }
}

push

새로운 요소를 힙에 추가한 후,
부모 노드와 비교하며 위로 올립니다. (bubbleUp)

1
2
3
4
5
6
7
8
const pq = new MinHeap();

pq.push(5);
pq.push(3);
pq.push(8);
pq.push(1);

// #heap : [1, 3, 8, 5]

pop

최소값(루트)을 제거한 후 마지막 요소를 루트로 옮기고 아래로 내립니다. (bubbleDown)

1
2
3
4
pq.pop(); // 1
pq.pop(); // 3

// #heap : [5, 8]

peek

우선순위가 가장 높은 요소(최소값) 를 확인합니다.

1
pq.peek(); // 5

size

힙의 요소 갯수를 확인합니다.

1
pq.size(); // 2
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.