게시글

5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭
강좌29 - Algorithm - 일 년 전 등록

자료구조(우선순위 큐, priority queue)

오랜만에 자료구조 포스팅으로 돌아왔습니다. 이번 시간에는 우선순위 큐를 구현해보도록 하겠습니다.

우선순위 큐는 에서 진화된 형태로, 맨 뒤에만 추가되고 맨 앞에서만 나가는 기본적인 FIFO 큐와는 다르게, 우선순위가 높은 노드가 먼저 나갈 수 있습니다. 따라서 일반적인 대기열이 아니라 중요도가 나눠져 있는 대기열을 구현할 때 좋습니다. 줄 서는 시스템에서 VIP를 우대한다든가(자본주의 세상!!!)... 태스크들이 있을 때 긴급 태스크를 먼저 처리하게 한다든가...

우선순위 큐는 (이진 힙)을 사용해서 구현할 수 있습니다. 힙에다 새로운 값을 넣는 게 우선순위 큐에 값을 넣는 것이고, 힙에서 값을 빼는게 우선순위 큐에 값을 제거하는 것입니다. 힙 소스코드에 데이터를 추가로 받게끔 수정하면 됩니다.

class PriorityQueue {
  arr = [];

  #reheapUp(self, idx) {
    if (idx) {
      const parent = parseInt((idx - 1) / 2);
      if (self.arr[idx].priority > self.arr[parent].priority) {
        const temp = self.arr[idx];
        self.arr[idx] = self.arr[parent];
        self.arr[parent] = temp;
        this.#reheapUp(self, parent);
      }
    }
  }

  #reheapDown(self, idx) {
    let left = 0;
    let right = 0;
    let large;
    if (idx * 2 + 1 < self.arr.length) {
      left = self.arr[idx * 2 + 1].priority;
      if (idx * 2 + 2 < self.arr.length - 1) {
        right = self.arr[idx * 2 + 2].priority;
      }
      if (left > right) {
        large = idx * 2 + 1;
      } else {
        large = idx * 2 + 2;
      }
      if (self.arr[idx].priority < self.arr[large].priority) {
        const temp = self.arr[idx];
        self.arr[idx] = self.arr[large];
        self.arr[large] = temp;
        this.#reheapDown(self, large);
      }
    }
  }
 
  insert(priority, data) {
    const last = this.arr.length;
    this.arr[last] = {}; // 객체로 변경
    this.arr[last].priority = priority;
    this.arr[last].data = data;
    this.#reheapUp(this, last);
    return true;
  };
 
  delete() {
    if (this.arr.length === 0) {
      return false;
    }
    const del = this.arr[0];
    this.arr[0] = this.arr.pop();
    this.#reheapDown(this, 0);
    return del.data;
  };
 
  peek() {
    return this.arr[0]?.data;
  };
}

insert 시 priority와 data를 받도록 수정했습니다. #reheapUp, #reheapDown에서도 priority를 기반으로 데이터를 교체합니다.

const pq = new PriorityQueue();
pq.insert(5, 'one');
pq.insert(3, 'two');
pq.insert(4, 'three');
pq.insert(2, 'four');
pq.insert(6, 'five');
pq.insert(1, 'six');
pq.insert(7, 'king'); // 새치기
pq.delete(); // 'king'
pq.peek(); // 'five'

FIFO 큐와 비교할 때 큐를 넣는 것, 빼는 것이 모두 O(lg(n))으로 시간 복잡도가 증가했지만 이 정도면 충분히 실전에서 사용할 수 있습니다.

우선순위 큐는 다른 자료구조로도 구현할 수는 있습니다. 정렬된 배열이나, 피보나치 힙, 이항 힙 등으로도 구현 가능합니다. 하지만 성능이 이진 힙보다 낮거나, 좋더라도 구현이 복잡하기에 이진 힙으로 만족하는 편입니다.

조회수:
0
목록
투표로 게시글에 관해 피드백을 해주시면 게시글 수정 시 반영됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright 2016- . 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.
5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭

댓글

아직 댓글이 없습니다.