[자료구조] 큐(Queue)
2021. 2. 23. 15:45ㆍFront-end/자료구조
728x90
반응형
큐(Queue)
- 스택이 LIFO(Last-In, First-Out) - 가장 나중에 들어온 것이 가장 먼저 나가는 구조 였다면
- 큐는 FIFO(First-In, First-Out) - 가장 먼저 들어온 것이 가장 먼저 나가는 구조(선입선출)
- 큐는 입구와 출구가 모두 뚫려있는 터널과 같은 형태로 시각화 할 수 있음.
- 예시
- 마트 계산대에서 줄을 서면 줄을 먼저 산 사람이 물건을 먼저 산다
- 모 대학교 카페 중에 '큐'라는 이름의 카페가 있다. 커피를 사려고 가장 먼저 줄을 선 사람이 먼저 커피를 주문한다
- 큐의 대표적인 사용 사례
- 프로세스 스케줄링
- 대부분의 입출력(파일 입출력 등)
- 프린터 대기열
- 네트워크 패킷 처리
- 게임 대기열(롤,오버워치)
- 큐의 대표적인 구현 방법
- 정적인 어레이(Fixed Array)
- 장점: 구현이 쉬움
- 단점: 고정된 Queue 크기
- 동적인 어레이(Linked List)
- 장점) 자유로운 Queue 크기
- 단점) 구현이 약간 더 어렵다
- 큐에서 사용할 메소드
- enqueue(원소(들)) : 큐의 뒤쪽에 원소(들)를 추가한다.
- dequeue() : 큐의 첫 번째 원소(큐의 맨 앞쪽에 위치한 원소)를 반환하고 큐에서 삭제한다.
- front() : 큐의 첫 번째 원소를 반환하되 큐 자체는 그대로 놔둔다(참조만 할 뿐 큐에서 원소를 삭제하지 않는다. stack에서 peek 메소드와 비슷하다.)
- isEmpty() : 큐가 비어있으면 true를, 비어있지 않으면 false를 반환한다.
- size() : 큐의 원소 개수를 반환한다. 배열의 length와 같다.
- clear() : 비우기
- print() : 디버깅 용도로 print 메소드 추가
큐 구현하기
class Queue{
constructor(){
this.arr = [];
}
enqueue(item){
this.arr.push(item);
} // enqueue는 뒤에서 원소를 넣어야 함(스택처럼 Array.push 메소드 사용)
dequeue(){
return this.arr.shift();
} // 앞에서 부터 지워야 하기 때문에 배열의 Array.shift 메소드 사용
front(){
return this.arr[0];
}
clear(){
this.arr = [];
}
isEmpty(){
return this.arr.length == 0;
}
size(){
return this.arr.length;
}
print(){
console.log(this.arr.toString());
}
}
let testQueue = new Queue();
console.log(testQueue.isEmpty()); // true
testQueue.enqueue("John");
testQueue.enqueue("Jack");
testQueue.enqueue("Camila");
testQueue.print(); //John,Jack,Camila
console.log(testQueue.size()); // 3
console.log(testQueue.isEmpty()); // false
testQueue.dequeue();
testQueue.dequeue();
testQueue.print(); //Camila
우선순위 큐(Priority Queue)
- 우선순위를 설정해 정확한 위치에 추가하는 것, 그리고 추가는 순서대로 하되, 삭제만 우선순위에 따른다.
- 예시
- 비행기 1등석,비즈니스석
- 병원 응급실
- 어떤 데이터가 우선순위가 높은지는 프로그래머가 직접 정해주면 된다.
- 우선순위 큐의 단점
- 데이터를 삽입하기 힘들다, 최악의 경우 성능이 떨어짐(삽입을 위한 적절한 위치를 찾기 위해 모든 인덱스를 탐색해야 하기 때문)
- → 그래서 주로 힙이라는 자료구조를 사용해서 구하는데, 힙을 알기 위해서는 또 트리를 알아야 한다.
우선순위 큐 구현하기
- 우선순위는 추가할 때는 순서대로, 삭제는 우선순위에 따라야 하므로
- 코드로 구현할 때에는 추가할 때 우선순위를 설정해서 원소를 정확한 위치에 추가하도록 한다.
class QElement {
constructor(element, priority) {
this.element = element;
this.priority = priority;
}
}
class PriorityQueue {
constructor() {
this.arr = [];
}
// <삽입 메소드 구현> 데이터의 우선순위에 따라 큐의 적절한 위치에 삽입
enqueue(element, priority) {
// QElement 객체 생성
const qElement = new QElement(element, priority);
let added = false;
// 전체 데이터를 순회하면서 자신의 우선순위가 더 높은 위치를 탐색
// splice 함수는 배열의 기존 요소를 삭제 또는 교체하거나 새 요소를 추가하여 배열의 내용을 변경
// array.splice(startIndex, deleteCount, item1, item2, ...)
for(let i=0; i < this.arr.length; i++) {
if(qElement.priority < this.arr[i].priority) {
this.arr.splice(i, 0, qElement);
added = true;
break;
}
}
// 큐에 자신보다 더 낮은 우선순위를 가진 요소가 없을 때, 큐의 맨 마지막에 삽입
if(!added) {
this.arr.push(qElement);
}
}
//<삭제 메소드 구현>
dequeue() {
return this.arr.shift();
}
//<유틸리티 메소드 구현>
front() {
return this.arr[0];
}
rear() {
return this.arr[this.arr.length-1];
}
isEmpty() {
return this.arr.length === 0;
}
print() {
let str ="";
this.arr.forEach((element) => str+= `(${element.element},${element.priority}),`)
console.log(`{${str}}`);
}
//{("Jack",1),("Camila",1),("John",2)}
}
let pq = new PriorityQueue();
pq.enqueue("John",2);
console.log(pq);
pq.enqueue("Jack",1);
pq.enqueue("Camila", 1);
pq.print();
환형 큐(Circular Queue)
예시 - 뜨거운 감자 게임
function hotPotato(nameList, number){
let queue = new Queue();
let eliminatePerson = '';
let winner;
for(let i = 0; i < nameList.length; i++){
queue.enqueue(nameList[i]);
}
while(queue.size() > 1){
let count = 1;
for(let i = 0; i < number; i++){
queue.enqueue(queue.dequeue());
}
eliminatePerson = queue.dequeue();
console.log(`${count}라운드: ${eliminatePerson}님을 퇴출시킵니다.`);
count++;
}
winner = queue.dequeue();
return winner;
}
let names=["m","j","h","d","h"];
let winner = hotPotato(names, 7);
console.log(`승자는 ${winner}님 입니다.`);
728x90
반응형
'Front-end > 자료구조' 카테고리의 다른 글
[자료구조] 집합 (0) | 2021.03.03 |
---|---|
[자료구조] 연결 리스트 - (2) doubly linked list (0) | 2021.03.03 |
[자료구조] 연결 리스트 - (1) Single Linked List (0) | 2021.03.02 |
재귀함수 (0) | 2021.02.24 |
[자료구조] 스택(Stack) (0) | 2021.02.22 |