2 분 소요

1. 우선순위 큐, Prority Queue

1.1 우선순위 큐란?

큐(Queue)는 먼저 들어오는 데이터가 먼저 나가는 FIFO(First In First Out)형식의 자료구조이다.
우선순위 큐(Priority Queue)는 먼저 들어오는 데이터가 아니라, 우선 순위가 높은 데이터가 먼저 나가는 형태의 자료구조이다.
우선순위 큐는 일반적으로 힙(Heap)을 이용해서 구현한다.

1.2 힙이란?

힙(Heap)은 우선순위 큐를 위해 고안된 완전이진트리 형태의 자료구조이다.
여러 개의 값 중 최댓값 또는 최솟값을 찾아내는 연산이 빠르다.

힙의 특징

  • 완전이진트리 형태로 이루어져 있다.
  • 부모노드와 서브트리간 대소 관계가 성립된다. (반 정렬 상태)
  • 이진탐색트리(BST)와 달리 중복된 값이 허용된다.

힙의 종류

  1. 최대 힙(Max Heap)
    부모 노드의 키 값이 자식 노드보다 크거나 같은 완전이진 트리이다. 최대힙
  2. 최소 힙(Min Heap)
    부모 노드의 키 값이 자식 노드보다 작거나 같은 완전이진트리이다. 최소힙

1.3 우선순위 큐 구현방법 비교

우선순위 큐를 힙이 아니라 배열 또는 연결리스트를 이용하여 구현할 수도 있다. 하지만 배열과 연결리스트는 선형 구조의 자료구조이므로 삽입 또는 삭제 연산을 위한 시간복잡도는 $O(n)$이다.

예를 들어 우선순위가 중간인 것이 들어가야 하는 삽입 과정에서는 뒤의 데이터까지 인덱스를 모두 한 칸씩 뒤로 밀어야 하는 단점이 있다.
최악의 경우 삽입해야 하는 위치를 찾기 위해 모든 인덱스를 탐색해야 한다, 즉 이 때의 시간 복잡도는 자료가 n개라고 할 때 $O(n)$ 이 된다.

반면 힙트리는 삭제나 삽입 과정에서 모두 보무와 자식 간의 비교만 계속 이루어진다. 즉, 이진 트리의 높이가 하나 증가할 때마다 저장 가능한 자료의 갯수는 2배 증가하며, 비교 연산 횟수는 1회 증가한다.그리고 완전이진트리 구조이므로 힙트리의 높이는 $log_{2}{(n+1)}$ 이며, 힙의 시간 복잡도는 $log_{2}{(n)}$ 이다.

이처럼 배열이나 연결 리스트가 삭제에서는 시간 복잡도를 우위를 점할지라도, 삽입의 시간 복잡도가 힙 기반이 월등하기 때문에 편차가 심한 배열과 연결리스트보다는 힙으로 구현하는 것이다.

2. 우선순위 큐 구현

2.1 힙 구현

힙은 일반적으로 배열을 이용하여 구현한다. 완전 이지느리미므로 중간에 비어있는 요소가 없기 때문이다. 힙

위 그림과 같이 트리의 각 노드에 번호를 붙이고, 이 번호를 배열의 인덱스로 생각하면 효과적으로 힙을 구현할 수 있다.
배열로 구현하였기 때문에 부모 또는 자식 노드를 찾아가는 연산을 구현하기도 간편하다.

  • 자식 노드를 구하고 싶을 때

    왼쪽 자식노드 Index = (부모 노드 Index) * 2 오른쪽 자식노드 Index = (부모 노드 Index) * 2 + 1

  • 부모 노드를 구하고 싶을 때

    부모 노드 Index = (자식 노드 Index) / 2

2.2 삽입 연산

힙에 삽입을 하기 위해서는 힙 트리의 성질을 만족시키면서 새로운 요소를 추가해야 한다.

삽입 방법

  • 우선 완전 이진 트리의 마지막 노드에 이어서 새로운 노드를 추가한다.
  • 추가된 새로운 노드를 부모의 노드와 비교하여 교환한다. 정상적인 힙트리가 될 때까지 (더 이상 부모노드와 교환할 필요가 없을 때까지) 반복한다.

최악의 경우 새로 추가된 노드가 루트노드까지 비교하며 올라가야 하므로 시간복잡도가 $O(log_{2}{n})$ 이다.

2.3 삭제 연산

힙 트리에서 루트노드가 가장 우선순위가 높으므로 루트 노드를 삭제해야 한다. 삭제가 이뤄진 후 힙 트리의 설징이 유지돼야 하므로 아래와 같은 방법으로 삭제를 진행한다.

삭제 방법\

  • 루트 노드를 삭제한다
  • 루트 노드가 삭제된 빈자리에 완전이진트리의 마지막 노드를 가져온다.
  • 루트 자리에 위치한 새로운 노드를 자식 노드와 비교하여 교환한다. 이때 최대 힙인 경우 자식 노드 중 더 큰 값과 교환을 하며, 최소 힙인 경우 더 작은 값과 교환한다.
  • 정상적인 힙트리가 될 때까지 (더 이상 자식노드와 교환할 필요가 없을 때까지) 반복한다.

삭제 연산 또한 최악의 경우 루트 노드부터 가장 아래까지 내려가야 하므로 시간복잡도가 $O(log_{2}{n})$ 이다.

Ref.

ChanBLOG-우선순위 큐
Suyeon’s Blog-우선순위 큐와 힙