1. 힙이란?
- O(1) 시간에 가장 높은 항목이나 가장 낮은 항목을 반환하는 중요한 자료구조.
- 힙은 트리와 비슷한 자료 구조의 일종
- 최대 힙의 경우 부모가 자식보다 크고, 최소 힙의 경우 부모가 자식보다 작음
- 다른 자료 구조와 달리 자식에 대한 포인터를 갖는 대신에 배열을 사용해 자료를 저장.
- 배열에서 힙 노드의 자식 위치(인덱스)를 쉽게 계산할 수 있음
- 힙을 사용하면 부모와 자식 간의 관계를 쉽게 정의할 수 있기 때문
2. 이진 힙
- 배열을 사용해 자료를 저장하기 때문에 배열의 인덱스는 각 항목의 차수/높이를 정의
- 첫 번째 배열 항목을 루트로 설정한 다음 각 왼쪽 항목과 오른쪽 항목을 순서대로 채움으로써 이진 힙을 만들 수 있음.

- 이진 힙의 종류: 최대 힙, 최소 힙
- 최대 힙: 루트노드가 가장 높은 값을 갖고 각 노드이 값이 자식의 값보다 큼

- 최소 힙: 루트 노드가 가장 낮은 값을 갖고 각 노드의 값이 자식의 값 보다 작음
- 힙은 문자열과 정수, 사용자의 정의 크랠스와 같이 어떤 종류의 값이든 저장할 수 있음
3. 이진 힙 배열 인덱스 구조
- 이진 힙의 경우 힙을 나타내기 위해 배열이 사용되는데 다믕과 같이 인덱스를 사용함
노드 |
인덱스 |
(자신) |
N |
부모 |
(N-1)/2 |
왼쪽 자식 |
(N*2)+1 |
오른쪽 자식 |
(N*2)+2 |
- N은 노드의 인덱스
- 힙에서 인덱스를 사용하여 부모-자식 간의 관계

- 일반적인 Heap Code
function Heap() {
this.items = [];
}
Heap.prototype.swap = function(idx1, idx2) {
let tmp = this.items[idx1];
this.items[idx1] = this.items[idx2];
this.items[idx2] = tmp;
}
Heap.prototype.parentIdx = function(idx) {
return Math.floor((idx-1)/2);
}
Heap.prototype.leftChildIdx = function(idx) {
return idx*2+1;
}
Heap.prototype.rightChildIdx = function(idx) {
return idx*2+1;
}
Heap.prototype.parent = function(idx) {
return this.items[this.parentIdx(idx)];
}
Heap.prototype.left = function(idx) {
return this.items[this.leftChildIdx(idx)];
}
Heap.prototype.right = function(idx) {
return this.items[this.rightChildIdx(idx)];
}
Heap.prototype.peek = function(item) {
return this.items[0];
}
Heap.prototype.size = function() {
return this.items.length;
}
3-1. 최소힙
- 삼투: 과학시간에 배웠던 것으로 농도가 높은 건 아래로, 낮은 건 위로 가는 현상인데, 최소힙의 자료 구조도 이와 비슷하다
- 항목을 추가하거나 삭제할 때 힙의 구조가 유지되야 함.(최대 힙의 경우 노드가 자식보다 커야 하고 최소 힙의 경우 노드가 자식보다 작아야 함)
- 최소힙의 시간 복잡도는 O(log2(N))
- [12,2,23,4,13]의 배열을 최소 힙에 삽입해 보면

- 최소힙 구현
function MinHeap() {
this.items=[];
}
MinHeap.prototype = Object.create(Heap.prototype);
MinHeap.prototype.add = function(item) {
this.items[this.items.length] = item;
this.bubbleUp();
}
MinHeap.prototype.poll = function() {
let item = this.items[0];
this.items[0] = this.items[this.items.length-1];
this.items.pop();
this.bubbleDown();
return item;
}
MinHeap.prototype.bubbleDown = function() {
let idx = 0;
while(this.leftChild(idx) && this.leftChild(idx) < this.items[idx] || this.rightChild(idx) < this.items[idx]) {
let smallerIdx = this.leftChildIdx(idx);
if(this.rightChild(idx) && this.rightChild(idx) < this.items[smallerIdx]) {
smallerIdx = this.rightChildIdx(idx);
}
this.swap(smallerIdx, idx);
idx = smallerIdx;
}
}
MinHeap.prototype.bubbleUp = function() {
let idx = this.items.length-1;
while(this.parent(idx) && this.parent(idx) > this.items[idx]) {
this.swap(this.parentIdx(idx), idx);
idx = this.parentIdx(idx);
}
}
let mh = new MinHeap();
mh.add(1);
mh.add(10);
mh.add(5);
mh.add(100);
mh.add(8);
console.log(mh.poll());
console.log(mh.poll());
console.log(mh.poll());
console.log(mh.poll());
console.log(mh.poll());
3-2. 최대힙
- [12,2,23,4,13]를 최대힙 구조로 만들 때

최종결과는 [23,13,12,2,4]
- 최대힙 구현
function MaxHeap() {
this.items=[];
}
MaxHeap.prototype = Object.create(Heap.prototype);
MaxHeap.prototype.add = function(item) {
this.items[this.items.length] = item;
this.bubbleUp();
}
MaxHeap.prototype.poll = function() {
let item = this.items[0];
this.items[0] = this.items[this.items.length-1];
this.items.pop();
this.bubbleDown();
return item;
}
MaxHeap.prototype.bubbleDown = function() {
let idx = 0;
while(this.leftChild(idx) && this.leftChild(idx) > this.items[idx] || this.rightChild(idx) > this.items[idx]) {
let biggerIdx = this.leftChildIdx(idx);
if(this.rightChild(idx) && this.rightChild(idx) > this.items[biggerIdx]) {
biggerIdx = this.rightChildIdx(idx);
}
this.swap(biggerIdx, idx);
idx = biggerIdx;
}
}
MaxHeap.prototype.bubbleUp = function() {
let idx = this.items.length-1;
while(this.parent(idx) && this.parent(idx) < this.items[idx]) {
this.swap(this.parentIdx(idx), idx);
idx = this.parentIdx(idx);
}
}
let mh = new MaxHeap();
mh.add(1);
mh.add(10);
mh.add(5);
mh.add(100);
mh.add(8);
console.log(mh.poll());
console.log(mh.poll());
console.log(mh.poll());
console.log(mh.poll());
console.log(mh.poll());