[algorithms] Queue

큐의 동작

  • 큐에 요소를 삽입하는 동작을 인큐(enqueue)
  • 큐에서 요소를 삭제하는 동작을 데큐(dequeue)
  • 인큐는 큐에 끝부분에 요소를 추가하며, 데큐는 큐의 앞부분에서 요소를 삭제한다.
  • 피크(peek)는 큐의 앞부분에 있는 요소를 확인할 수 있다. 또한 요소를 반환하지는 않는다.
  • length 프로퍼티를 이용하면 큐에 얼마나 많은 요소가 저장되어 있는지 확인 할 수 있다.

큐 구현

class Queue<T> {
  dataStore: T[];

  constructor(dataStore?: T[]) {
    this.dataStore = dataStore || [];
  }

  get length() {
    return this.dataStore.length;
  }

  enqueue(element: T) {
    this.dataStore.push(element);
  }

  dequeue() {
    // 배열에서 첫 번째 요소를 제거하고, 제거된 요소를 반환
    return this.dataStore.shift();
  }

  // 큐의 앞부분의 요소를 확인한다.
  front() {
    return this.dataStore[0];
  }

  // 큐의 끝부분의 요소를 확인한다.
  back() {
    return this.dataStore[this.dataStore.length - 1];
  }

  toString() {
    return this.dataStore.join("\n");
  }

  // 큐가 비었는지 안비었는지 확인한다.
  empty() {
    if (this.dataStore.length === 0) return true;
    return false;
  }

  [Symbol.iterator]() {
    let position = -1;
    const dataList = this.dataStore;
    const length = this.length;
    return {
      next() {
        position = position + 1;
        return {
          value: dataList[position],
          done: position >= length
        };
      }
    };
  }
}

예제

  1. 큐로 데이터 정렬하기 (기수정렬)

기수 정렬은 두 번의 과정을 걸쳐 데이터를 정렬한다. 우리는 0 부터 99 사이의 정수 데이터를 사용한다. 첫 번째 과정에서는 1의 자리 숫자를 기준으로 숫자를 정렬하고 , 두 번째 과정에서는 10의 자리 숫자를 기주능로 데이터를 정렬한다.

type DigitType = 1 | 10;
const sampleList = [10, 29, 40, 50, 32, 54, 34, 56, 23, 97, 78];

// digit 정렬 기준 자릿수
function distribute(targetList: number[], digit: DigitType) {
  const result: Queue<number>[] = new Array(10).fill(1).map(_ => new Queue());

  targetList.forEach(num => {
    if (digit === 1) {
      const rest = num % 10;
      result[rest].enqueue(num);
    } else {
      const rest = Math.floor(num / 10);
      result[rest].enqueue(num);
    }
  });

  return result;
}

function collect(queueList: Queue<number>[]) {
  return queueList.flatMap(queue => {
    // return queue.dataStore
    const queueDataList = [];
    for (const value of queue) {
      queueDataList.push(value);
    }
    return queueDataList;
  });
}

const firstQueue = distribute(sampleList, 1);
const firstCollectList = collect(firstQueue);
const secondQueue = distribute(firstCollectList, 10);
const result = collect(secondQueue);

console.log("sampleList", sampleList);
console.log("result", result);
  1. 우선순위 큐

보통 큐에서 요소를 삭제할 때는 먼저 삽입한 요소부터 삭제된다. 하지만 이러한 선입선출 방식이 아닌 우선순위와 같은 다른 기준으로 요소를 삭제해야하는 경우도 있다. 이럴때는 우선순위 큐라는 자료구조를 이용한다.

// 기존 queue 에서 dequeue를 수정해 준다.
// 다음과 같은 큐에 들어갈 element가 있다고 가정하자.

class Job {
  name: string
  code: number

  constructor(name:string, code:number) {
    this.name = name;
    this.code = code;
  }
}

const queue = new Queue<Job>()

// 기존 큐에서 dequeue는 다음과 같이 수정해 준다.
class Queue {
  // (...)
  dequeue() {
     const targetIndex = this.dataStore.reduce((resultIndex, elem, index) => {
      if(resultIndex > elem.code) {
        return index
      }
      return resultIndex
    },0)
  }
}
© 2021 Merlin.ho, Built with Gatsby