완전 이진 트리의 일종으로, 각 노드의 키 값이 자식의 키 값보다 작지 않거나(=최대 힙), 크지 않은(=최소 힙) 트리
완전이진트리란?
루트 노드 → 왼쪽 자식 → 오른쪽 자식 순으로 데이터 삽입되는 트리 형태
Heap은 항상 루트 노드를 제거하는 식으로 동작
O(N)
이지만, Heap 사용 시 O(1)
로 낮출 수 있음O(logN)
Math.floor((본인 인덱스-1)/2)
본인 인덱스 * 2 +1
본인 인덱스 * 2 +2
class PriorityQueue {
constructor() {
this.heap = []; // 빈 배열 생성
}
getLeftChildIndex = (parentIndex) => parentIndex * 2 + 1; // 왼쪽 자식 인덱스
getRightChildIndex = (parentIndex) => parentIndex * 2 + 2; // 오른쪽 자식 인덱스
getParentIndex = (childIndex) => Math.floor((childIndex - 1) / 2); // 부모 인덱스
peek = () => this.heap[0].key; // 루트 노드 반환
size = () => this.heap.length; // heap 배열 크기 반환
isEmpty = () => this.heap.length === 0;
// 원소 삽입
enqueue = (key, value) => {
const node = { key, value }; // 우선순위 비교를 위해 노드 형태로 저장
this.heap.push(node); // 새 원소 마지막 위치에 삽입
this.heapifyUp(); // 정렬 수행
};
// 아래에서 위로 정렬
heapifyUp = () => {
let index = this.size() - 1; // 마지막 인덱스
const lastNode = this.heap[index]; // 마지막 원소
while (index > 0) {
const parentIdx = this.getParentIndex(index); // 부모 인덱스 찾기
// 부모 원소의 종료 시간이 자식 원소 종료시간보다 큰 경우 swap
if (this.heap[parentIdx].key > lastNode.key) {
this.heap[index] = this.heap[parentIdx];
index = parentIdx;
} else break;
}
this.heap[index] = lastNode; // 본인 자리 찾아가기
};
// 원소 삭제
dequeue = () => {
if (this.isEmpty()) return null; // 비어있는 경우 삭제 불가능
const rootNode = this.heap[0];
if (this.heap.length === 1) this.heap = [];
else {
this.heap[0] = this.heap.pop(); // 맨 마지막에 있는 원소 루트로 이동
this.heapifyDown(); // 정렬 수행
}
return rootNode; // 루트 노드 반환
};
// 위에서 아래로 정렬
heapifyDown = () => {
let index = 0;
const heapSize = this.size();
const rootNode = this.heap[index];
while (this.getLeftChildIndex(index) < heapSize) {
const leftChildIdx = this.getLeftChildIndex(index); // 왼쪽 자식 인덱스
const rightChildIdx = this.getRightChildIndex(index); // 오른쪽 자식 인덱스
// 부모노드가 자식 노드들보다 값이 큰 경우 swap
// 왼쪽 자식 노드와 오른쪽 자식 노드 중 더 작은 값을 가지는 인덱스와 부모 노드랑 변경
const smallerChildIndex =
rightChildIdx < heapSize &&
this.heap[rightChildIdx].key < this.heap[leftChildIdx].key
? rightChildIdx
: leftChildIdx;
// 자식 노드 값이 부모 노드보다 작은 경우 swap
if (this.heap[smallerChildIndex].key <= rootNode.key) {
this.heap[index] = this.heap[smallerChildIndex];
index = smallerChildIndex;
} else break;
}
this.heap[index] = rootNode;
};
}
JavaScript로 Heap | Priority Queue 구현하기
[자료구조] 자바스크립트로 우선순위 큐(Priority Queue) 구현하기
힙 (최소 힙, 최대 힙)