힙의 조건 : 완전 이진 트리이며 , 아래에서 설명할 최대 힙 , 최소 힙의 조건을 충족 해야한다.
class MaxHeapTree {
// 편리한 구현을 위해 index는 1부터 사용
constructor() {
this._items = [""];
}
get items() {
return this._items;
}
get root() {
return _items[1];
}
/**
* 구현 절차
* - 1) 힙의 가장 마지막 위치(배열의 마지막)에 노드에 추가한다
* - 2) 힙의 조건을 만족시키도록 연산 (부모노드와 교환)
* - 새로 추가한 노드와 부모 노드를 비교하여 부모노드가 더 작으면 위치를 바꾼다
* - (더 큰 부모노드가 없을때까지 반복)
*/
insert(key) {
this._items.push(key);
this._allignAfterInsert();
}
/**
* 힙의 삭제는 루트 노드 삭제만 구현한다. (queue의 pop 연산이라고 생각하면 됨)
*
* 구현 절차
* - 1) 루트노드를 제거
* - 2) 제거한 루트노드자리에 마지막 노드를 삽입
* - 3) 힙의 조건을 만족시키도록 연산
* - 루트노드의 자식노드 중 더 큰 값과 교환한다.
* - (더 큰 자식노드가 없을때까지 반복)
*/
remove() {
this._items[1] = this._items.pop();
this._allignAfterRemove();
}
_allignAfterInsert() {
let childIndex = this._items.length - 1;
let child = this._items[childIndex];
let parentIndex = Math.floor(childIndex / 2) || 1;
let parent = this._items[parentIndex];
let newChildIndex;
while (parent < child) {
newChildIndex = parentIndex;
this._items[newChildIndex] = child;
this._items[childIndex] = parent;
parentIndex = Math.floor(newChildIndex / 2) || 1;
parent = this._items[parentIndex];
childIndex = newChildIndex;
}
}
_allignAfterRemove() {
let parentIndex = 1;
let parent = this._items[parentIndex];
let leftChild = this._items[parentIndex * 2];
let rightChild = this._items[parentIndex * 2 + 1];
let bigChild = leftChild > rightChild ? leftChild : rightChild;
let bigChildIndex = this._items.indexOf(bigChild);
let newParentIndex;
while (parent < bigChild) {
newParentIndex = bigChildIndex;
this._items[newParentIndex] = parent;
this._items[parentIndex] = bigChild;
leftChild = this._items[newParentIndex * 2];
rightChild = this._items[newParentIndex * 2 + 1];
bigChild = leftChild > rightChild ? leftChild : rightChild;
bigChildIndex = this._items.indexOf(bigChild);
parentIndex = newParentIndex;
}
}
}
// Test
it("MaxHeapTree 클래스는 잘 동작한다.", () => {
const heap = new MaxHeapTree();
heap.insert(9);
heap.insert(3);
heap.insert(5);
heap.insert(10);
heap.insert(6);
expect(heap.items).toEqual(["", 10, 9, 5, 3, 6]);
heap.insert(8);
expect(heap.items).toEqual(["", 10, 9, 8, 3, 6, 5]);
heap.remove();
expect(heap.items).toEqual(["", 9, 6, 8, 3, 5]);
heap.remove();
expect(heap.items).toEqual(["", 8, 6, 5, 3]);
});
class MinHeapTree {
// 편리한 구현을 위해 index는 1부터 사용
constructor() {
this._items = [""];
}
get items() {
return this._items;
}
get root() {
return _items[1];
}
/**
* 구현 절차
* - 1) 힙의 가장 마지막 위치(배열의 마지막)에 노드에 추가한다
* - 2) 힙의 조건을 만족시키도록 연산 (부모노드와 교환)
* - 새로 추가한 노드와 부모 노드를 비교하여 부모노드가 더 크면 위치를 바꾼다
* - (더 큰 부모노드가 없을때까지 반복)
*/
insert(key) {
this._items.push(key);
this._allignAfterInsert();
}
/**
* 힙의 삭제는 루트 노드 삭제만 구현한다. (queue의 pop 연산이라고 생각하면 됨)
*
* 구현 절차
* - 1) 루트노드를 제거
* - 2) 제거한 루트노드자리에 마지막 노드를 삽입
* - 3) 힙의 조건을 만족시키도록 연산
* - 루트노드의 자식노드 중 더 작은 값과 교환한다.
* - (더 작은 자식노드가 없을때까지 반복)
*/
remove() {
this._items[1] = this._items.pop();
this._allignAfterRemove();
}
_allignAfterInsert() {
let childIndex = this._items.length - 1;
let child = this._items[childIndex];
let parentIndex = Math.floor(childIndex / 2) || 1;
let parent = this._items[parentIndex];
let newChildIndex;
while (parent > child) {
newChildIndex = parentIndex;
this._items[newChildIndex] = child;
this._items[childIndex] = parent;
parentIndex = Math.floor(newChildIndex / 2) || 1;
parent = this._items[parentIndex];
childIndex = newChildIndex;
}
}
_allignAfterRemove() {
let parentIndex = 1;
let parent = this._items[parentIndex];
let leftChild = this._items[parentIndex * 2];
let rightChild = this._items[parentIndex * 2 + 1];
let smallChild = leftChild < rightChild ? leftChild : rightChild;
let smallChildIndex = this._items.indexOf(smallChild);
let newParentIndex;
while (parent > smallChild) {
newParentIndex = smallChildIndex;
this._items[newParentIndex] = parent;
this._items[parentIndex] = smallChild;
leftChild = this._items[newParentIndex * 2];
rightChild = this._items[newParentIndex * 2 + 1];
smallChild = leftChild < rightChild ? leftChild : rightChild;
smallChildIndex = this._items.indexOf(smallChild);
parentIndex = newParentIndex;
}
}
}
// Test
it("MinHeapTree 클래스는 잘 동작한다.", () => {
const heap = new MinHeapTree();
heap.insert(9);
heap.insert(3);
heap.insert(5);
heap.insert(10);
heap.insert(6);
expect(heap.items).toEqual(["", 3, 6, 5, 10, 9]);
heap.insert(2);
expect(heap.items).toEqual(["", 2, 6, 3, 10, 9, 5]);
heap.remove();
expect(heap.items).toEqual(["", 3, 6, 5, 10, 9]);
heap.remove();
expect(heap.items).toEqual(["", 5, 6, 9, 10]);
});
class Heap {
constructor(size) {
if (size && isNaN(size)) throw Error(`Invalidate param`);
this.idx = 0;
this.arr = new Array(size ? size : 11).fill(null);
}
add(n) {
if (this.idx + 1 === this.arr.length) throw Error(`Stack overflow`);
let idx = ++this.idx;
this.arr[idx] = n;
while (idx > 1) {
const nextIdx = idx >> 1;
const parent = this.arr[nextIdx];
const cur = this.arr[idx];
if (parent <= cur) break;
this.arr[nextIdx] = cur;
this.arr[idx] = parent;
idx >>= 1;
}
return true;
}
print() {
console.log(this.arr);
}
pop() {
if (this.idx === 0) throw Error(`Empty stack`);
const ret = this.arr[1];
let idx = 1;
this.arr[1] = this.arr[this.idx];
this.arr[this.idx--] = null;
while (idx < this.idx) {
if (idx * 2 > this.idx || idx * 2 + 1 > this.idx) break;
let nextIdx = idx * 2;
if (this.arr[idx] <= this.arr[nextIdx]) nextIdx = idx;
if (this.arr[nextIdx] > this.arr[idx * 2 + 1]) nextIdx = idx * 2 + 1;
if (nextIdx === idx) break;
const tmp = this.arr[idx];
this.arr[idx] = this.arr[nextIdx];
this.arr[nextIdx] = tmp;
idx = nextIdx;
}
return ret;
}
peek() {
return this.arr[this.idx];
}
}
function main() {
const heap = new Heap();
for (let i = 10; i > 0; i--) {
heap.add(i);
}
heap.print();
while (heap.peek()) {
console.log(heap.pop(), heap.idx);
heap.print();
}
}
main();
const Heap = function Heap() {
this.heap = Array(30).fill(' ');
this.heapSize =0;
}
Heap.prototype.insertHeap = function(data) {
const heap = this.heap;
const newData = data;
if(this.heapSize === 0) {
heap[1] = newData;
this.heapSize++;
}else {
this.heapSize++
let idx = this.heapSzie;
heap[idx] = newData;
// 데이터를 넣었으면 비교 연산
let parentIdx = parseInt(idx/2);
while(parentIdx > 0) {
if(heap[parentIdx]< heap[idx]) {
let temp = heap[parentIdx];
heap[parentIdx] = heap[idx];
heap[idx] = temp;
}else{
break;
parentIdx = parseInt(parseInt / 2);
}
}
}
}
Heap.prototype.printAll = function () {
let result = "";
for(let i=0; i< this.heapSize; i++) {
result += `${this.heap[i]}`;
console.log("출력", result);
}
}
Heap.prototype.deleteHeap = function() {
const lastIdx = this.heapSize;
const heap = this.heap;
const deleteVal = heap[i];
let idx = 1;
console.log(heap);
heap[1] = heap[lastIdx];
heap[lastIdx] = "";
while(heap[idx * 2] !== "" && heap[idx*2+1] !=="") {
let temp = 0;
if(heap[idx] < heap[idx*2]){
temp = heap[idx];
heap[idx] = heap[idx*2];
heap[idx*2] = temp;
idx *= 2;
}
else if(heap[idx] < heap[idx*2+1]) {
temp = heap[idx];
heap[idx] = heap[idx*2+1];
heap[idx*2+1] = temp;
idx = idx*2+1;
}else{
break;
}
}
console.log(`${delteVal} 삭제완료` );
}
function main() {
const heap = new Heap();
heap.insertHeap(23);
heap.insertHeap(19);
heap.insertHeap(10);
heap.insertHeap(15);
heap.insertHeap(9);
heap.insertHeap(13);
heap.deleteHeap();
heap.printAll();
}
main();