
heap의 대표적인 기능으로는 3가지가 있다
알고리즘에서 가장 활용성이 높은 Min Heap을 구현해 보겠다.
// 새로운 값을 추가 후 정렬 (bubble up)
insert(value) {
this.heap.push(value) // 새로운 노드 추가
this.bubbleUp( this.heap.length -1 ) // bubble up 정렬
}
bubbleUp(idx) {
while ( idx > 0 ) {
const parentIdx = Math.floor((idx-1)/2) // 부모 노드 계산
// 자식 노드가 부모 노드보다 작을 경우
if ( this.heap[parentIdx][1] > this.heap[idx][1] ) {
// 자식과 부모 노드 위치를 바꿈
[ this.heap[idx], this.heap[parentIdx] ] = [ this.heap[parentIdx], this.heap[idx] ]
idx = parentIdx // 인덱스를 부모 노드의 인덱스로 교체
} else { // 정렬 완료
break
}
}
}
// 루트 값을 반환 후 정렬 (bubble down)
delete() {
// Heap에 값이 하나뿐이면 pop()으로 바로 반환
if (this.heap.length === 1) return this.heap.pop()
const min = this.heap[0]
this.heap[0] = this.heap.pop() // 마지막 노드를 루트로 이동
this.bubbleDown(0) // bubble down 정렬
return min // 최소값 return
}
bubbleDown(idx) {
const length = this.heap.length // 힙의 범위
while (true) {
let smallest = idx // 현재 노드의 index
const left = idx * 2 + 1 // 왼쪽 자식 노드의 index
const right = idx * 2 + 2 // 오른쪽 자식 노드의 index
// 범위를 벗어나지 않으면서 현재 노드 보다 왼쪽 자식 노드가 작을 경우
if ( left < length && this.heap[left][1] <this.heap[smallest][1] ) {
smallest = left
}
// 범위를 벗어나지 않으면서 현재 노드 보다 오른쪽 자식 노드가 작을 경우
if ( right < length && this.heap[right][1] < this.heap[smallest][1] ) {
smallest = right
}
// 현재 노드보다 작을 자식 노드가 있었을 경우 교체
if ( smallest !== idx ) {
[ this.heap[smallest], this.heap[idx] ] = [ this.heap[idx], this.heap[smallest] ]
idx = smallest
} else { // 없을 경우 종료
break
}
}
}
// 루트 값 확인
peek() {
return this.heap[0] ?? null
}
class MinHeap {
constructor() {
this.heap = []
}
// 새로운 값을 추가 후 정렬 (bubble up)
insert(value) {
this.heap.push(value) // 새로운 노드 추가
this.bubbleUp( this.heap.length -1 ) // bubble up 정렬
}
bubbleUp(idx) {
while ( idx > 0 ) {
const parentIdx = Math.floor((idx-1)/2) // 부모 노드 계산
// 자식 노드가 부모 노드보다 작을 경우
if ( this.heap[parentIdx][1] > this.heap[idx][1] ) {
// 자식과 부모 노드 위치를 바꿈
[ this.heap[idx], this.heap[parentIdx] ] = [ this.heap[parentIdx], this.heap[idx] ]
idx = parentIdx // 인덱스를 부모 노드의 인덱스로 교체
} else { // 정렬 완료
break
}
}
}
// 루트 값을 반환 후 정렬 (bubble down)
delete() {
// Heap에 값이 하나뿐이면 pop()으로 바로 반환
if (this.heap.length === 1) return this.heap.pop()
const min = this.heap[0]
this.heap[0] = this.heap.pop() // 마지막 노드를 루트로 이동
this.bubbleDown(0) // bubble down 정렬
return min // 최소값 return
}
bubbleDown(idx) {
const length = this.heap.length // 힙의 범위
while (true) {
let smallest = idx // 현재 노드의 index
const left = idx * 2 + 1 // 왼쪽 자식 노드의 index
const right = idx * 2 + 2 // 오른쪽 자식 노드의 index
// 범위를 벗어나지 않으면서 현재 노드 보다 왼쪽 자식 노드가 작을 경우
if ( left < length && this.heap[left][1] <this.heap[smallest][1] ) {
smallest = left
}
// 범위를 벗어나지 않으면서 현재 노드 보다 오른쪽 자식 노드가 작을 경우
if ( right < length && this.heap[right][1] < this.heap[smallest][1] ) {
smallest = right
}
// 현재 노드보다 작을 자식 노드가 있었을 경우 교체
if ( smallest !== idx ) {
[ this.heap[smallest], this.heap[idx] ] = [ this.heap[idx], this.heap[smallest] ]
idx = smallest
} else { // 없을 경우 종료
break
}
}
}
// 루트 값 확인
peek() {
return this.heap[0] ?? null
}
}