자료구조 & 알고리즘

[자료구조] 우선순위 큐(Priority Queue) 메서드 구현하기

진기명기 2023. 3. 16. 09:22
🫠 큐에 우선순위를 두면 어떻게 될까? 큐의 대표적인 특징인 FIFO에서 데이터에 우선순위를 넣어, 우선순위를 고려한 데이터가 먼저 나오는 FIFO 기반의 선형 자료 구조를 만들어보자!

 

 

 

🫠 우선순위가 포함된 큐 생성자 함수를 만들어보자

// Element() : 데이터와 우선순위를 저장하기 위한 생성자 함수
function Element(data, priority){
  this.data = data
  this.priority = priority
}


// PriorityQueue() : Elemnet 관리를 위한 생성자 함수
function PriorityQueue() {
  this.array = []
}


// getBuffer() : 객체 내 데이터 셋 반환
PriorityQueue.prototype.getBuffer = function(){
  return this.array.map((element) => element.data)
}

// isEmpty() : 객체 내 데이터 존재 여부 파악
PriorityQueue.prototype.isEmpty = function(){
  return this.array.length === 0
}
✅ Element 생성자 함수는 element에 data와 priority 즉, 우선순위만 저장해 주는 역할을 한다.
✅ 실제 Element를 관리해주는 함수는 PriorityQueue()가 해당
✅ getBuffer() 메서드에서 slice()를 사용하지 않고, map()을 통해 배열 내에 요소를 순차적으로 하나씩 돌아 data를 복사한다.
✅ isEmpty()는 변경된 코드 없이 똑같이 사용할 수 있다.

 

 

 

❗️ Element 생성자 함수와 PriorityQueue 생성자 함수의 메서드를 출력해 보자

console.log(Object.getOwnPropertyDescriptors(Element.prototype))
/*
{
  constructor: {
    value: [Function: Element],
    writable: true,
    enumerable: false,
    configurable: true
  }
}
*/
console.log(Object.getOwnPropertyDescriptors(PriorityQueue.prototype))
/*
{
  constructor: {
    value: [Function: PriorityQueue],
    writable: true,
    enumerable: false,
    configurable: true
  },
  getBuffer: {
    value: [Function (anonymous)],
    writable: true,
    enumerable: true,
    configurable: true
  },
  isEmpty: {
    value: [Function (anonymous)],
    writable: true,
    enumerable: true,
    configurable: true
  }
}
✅ Element 생성자 함수 data와 priority만 저장하기 때문에 다른 메서드는 없는 것을 확인할 수 있다.
✅ PriorityQueue 생성자 함수에는 getBuffer()와 isEmpty() 메서드가 있는 것을 확인할 수 있다. 

 

 

 


🫠 우선순위 큐 enqueue() & dequeue() 메서드 구현하기

// enqueue() : 데이터 추가
PriorityQueue.prototype.enqueue = function(data, priority){
  let element = new Element(data, priority)
  let added = false // 아직 받은 element가 없으므로

  for(let i = 0; i < this.array.length; i++){
    if(element.priority < this.array[i].priority) {// 새로 들어온 element의 숫자(우선순위)가 현재 배열에 있는 priority보다 작으면(우선순위가 높으면)
      this.array.splice(i, 0, element) // splice -> i번째에 있는 데이터를, 0개만큼 지워라, 그리고 element를 추가해라
      added = true // element를 배열에 추가했다면 true
      break // for문을 빠져나와라
    }
  }

  if(!added){ // 만약 element가 추가되지 않았다면, 맨 마지막 순위이므로 뒤에 push
    this.array.push(element)
  }

  return this.array.length
}


// dequeue() : 데이터 삭제
PriorityQueue.prototype.dequeue = function(){
  return this.array.shift()
}
✅ 주석 처리 설명 확인
✅ splice()는 해당 위치에서부터 데이터를 지정한 개수만큼 삭제하는 것이 특징이지만, splice(i, 0, element)처럼 삭제할 데이터를 0개로 지정한 경우, 삭제되는 데이터는 없으며 element만 해당 위치에 추가된다.
✅ dequeue()는 변경된 코드 없이, 이전 시간에 작성한 코드와 같다.

 

 

 

❗️ 해당 메서드 실행해서 결과 확인해 보자

// user 객체 생성(우선순위 확인)
let user = new PriorityQueue()

user.enqueue('YJ', 1)
user.enqueue('SH', 2)
console.log(user)
/*
PriorityQueue {
  array: [
    Element { data: 'YJ', Priority: 1 },
    Element { data: 'SH', Priority: 2 }
  ]
}
*/


// user 객체에 우선순위 1과 3 추가
user.enqueue('JH', 1)
user.enqueue('HY', 3)
console.log(user)
/*
PriorityQueue {
  array: [
    Element { data: 'YJ', priority: 1 },
    Element { data: 'JH', priority: 1 },
    Element { data: 'SH', priority: 2 },
    Element { data: 'HY', priority: 3 }
  ]
}
*/


// dequeue() 실행 확인
console.log(user.dequeue()) // Element { data: 'YJ', priority: 1 }
console.log(user)
/*
PriorityQueue {
  array: [
    Element { data: 'JH', priority: 1 },
    Element { data: 'SH', priority: 2 },
    Element { data: 'HY', priority: 3 }
  ]
}
*/
✅ 두 번째 문단 enqueue() 실행 결과를 보면 처음에 추가했던 'YJ', 'SH' 사이에 'JH'가 우선순위 '1'로 인해 들어온 것을 확인할 수 있다. 'HY'는 우선순위가 가장 낮으므로 맨 끝에 추가.
✅ 세 번째 문단 dequeue()를 실행한 경우, 가장 앞 데이터인 'YJ'의 데이터가 삭제된 것을 확인할 수 있다.

 

 

 


❗️ 우선순위 큐의 또 다른 메서드 

// front() : 가장 첫 데이터 반환
PriorityQueue.prototype.front = function(){
  return this.array.length === 0 ? undefined : this.array[0].data
}


// size() : 큐 내 데이터 개수 반환
PriorityQueue.prototype.size = function(){
  return this.array.length
}


// clear() : 큐 내 데이터 초기화
PriorityQueue.prototype.clear = function(){
  this.array = []
}


// 실행
console.log(user)
/*
PriorityQueue {
  array: [
    Element { data: 'JH', priority: 1 },
    Element { data: 'SH', priority: 2 },
    Element { data: 'HY', priority: 3 }
  ]
}
*/
console.log(user.front()) // JH
console.log(user.size()) // 3
✅ front(), size(), clear() 메서드는 기존과 같기 때문에 따로 설명은 하지 X
✅ 메서드 실행 주석 처리 확인하자