위키백과에서 본 힙 자료:
최대/최소 힙 정렬 참고로 봤던 자료:
https://nyang-in.tistory.com/153
최소 힙과 힙 참고시 공부한 코드(위 블로그에 내용 있음)
감을 익히기 위해 코딩하면서 참고했다.
힙 코드
class heap {
constructor(){
this.items = [];
}
//값을 서로 바꾸는 메소드
swap(index1, index2){
let temp = this.items[index1];
//items의 index1의 값을 temp(임시공간)에 담음
this.items[index1] = this.items[index2]
//index1에 index2 값 저장
this.items[index2] = temp;
//index2에 temp값 저장
}
//부모 인덱스 구하는 메소드
parentIndex(index){
return Math.floor((index - 1) / 2);
}
//왼쪽 자식 인덱스 구하는 메소드
leftChildIndex(index){
return index * 2 + 1;
}
//오른쪽 자식 인덱스 구하는 메소드
rightChildIndex(index){
return index * 2 + 2;
}
//부모 노드 구하는 메소드
parent(index){
return this.items[this.parentIndex(index)];
}
//왼쪽 자식 노드 구하는 메소드
leftChild(index){
return this.items[this.leftChildIndex(index)];
}
//오른쪽 자식 노드 구하는 메소드
rightChild(index){
return this.items[this.rightChildIndex(index)];
}
//최대 힙의 경우 최댓값을 반환하고 최소힙의 경우 최솟값을 반환하는 메소드
peek(){
return this.items[0];
}
//힙의 크기(항목 개수)를 반환하는 메소드
size(){
return this.items.length;
}
}
힙 코드를 상속한 최소 힙 코드
import "./heap"
class minHeap extends heap{
//minHeap은 Heap 클래스를 상속받음
bubbleUp(){
let index = this.items.length - 1;
while(this.parent(index) !==undefined && this.parent(index) > this.items[index]){
this.swap(index, this.parentIndex(index));
index = this.parentIndex(index);
}
}
bubbleDown(){
let index = 0;
while(this.leftChild(index) !==undefined && (this.leftChild(index) < this.items[index] || this.rightChild(index) < this.items[index])){
let smallerIndex = this.leftChildIndex(index);
if(this.rightChild(index) !==undefined && this.rightChild(index) <this.items[smallerIndex] ){
smallerIndex = this.rightChildIndex(index);
}
this.swap(index, smallerIndex);
index = smallerIndex;
}
}
//힙에 원소를 추가하는 함수
add(item){
this.items[this.items.length] = item;
this.bubbleUp();
}
//힙에서 원소를 빼내는 함수
//최소 힙이라면 최솟값이 빠져나올 것이고 최대힙이면 최댓값이 빠져나옴
poll(){
let item = thsi.items[0] //첫 원소 keep
this.items[0] = this.items[this.items.length - 1]; //맨 마지막 원소를 첫번째 원소로 복사
this.items.pop(); //맨 마지막 원소 삭제
this.bubbleDown();
return item; //keep 해둔 값 반환.
}
}
문제 설명: 정수를 요소로 갖는 중첩되지 않은 1차원 배열을 입력받는다. 이후 arr.sort를 사용하지 않고 힙정렬을 구현해야한다.
최소 힙 정렬을 구현해야하며 문제를 풀기 전 이진 힙정렬과 최대/최소 힙정렬을 공부할 것을 추천한다.
입력
인자 1 : arr
출력
주의사항
입출력 예시
let output = heapSort([5, 4, 3, 2, 1]);
console.log(output); // --> [1, 2, 3, 4, 5]
output = heapSort([3, 1, 21]);
console.log(output); // --> [1, 3, 21]
output = heapSort([4, 10, 3, 5, 1]);
console.log(output); // --> [1, 3, 4, 5, 10]
풀이 코드
각 함수의 역할
//arr 배열에서 idx1, idx2의 위치를 교환하는 함수
function swap(idx1, idx2, arr) {
[arr[idx1], arr[idx2]] = [arr[idx2], arr[idx1]];
}
//부모노드의 인덱스를 구하는 함수
function getParentIdx(idx) {
// TODO: 여기에 코드를 작성합니다.
return Math.floor((idx - 1) / 2);
}
//heap에 item을 insert함
//삽입하는 함수
//heap 배열의 크기가 1 초과일때 조건문 작동
//부모인덱스 0 이상이고 부모인덱스가 현재 인덱스보다 클 경우 무한 루프
//curIdx(현재 인덱스)와 pIdx의 위치를 교환한 뒤 heap을 반환.
function insert(heap, item) {
console.log("before heap",heap )
// TODO: 여기에 코드를 작성합니다.
heap.push(item);
if (heap.length > 1) {
let curIdx = heap.length - 1;
let pIdx = getParentIdx(curIdx);
console.log("curIdx", curIdx,"pIdx", pIdx)
//curIdx가 pIdx 미만일 때 무한루프
console.log("before while heap",heap)
while (pIdx >= 0 && heap[curIdx] < heap[pIdx]) {
//heap 배열에서 curIdx와 pIdx 위치 교환
swap(curIdx, pIdx, heap);
//curIdx에 pIdx 값 대입
curIdx = pIdx;
//pIdx는 curIdx의 부모인덱스 값 대입
pIdx = getParentIdx(curIdx);
}
}
console.log("after heap",heap )
return heap;
}
function removeRoot(heap) {
//heap 배열에서 인덱스 0과 마지막을 교환
swap(0, heap.length - 1, heap);
//heap 마지막 원소 제거
heap.pop();
//힙 배열의 크기가 0 이면 빈 배열로 리턴
if (heap.length === 0) return [];
//curIdx, minIdx 각각 값 선언
let curIdx;
let minIdx = 0;
//curIdx와 minIdx가 같지 않을 때 무한 루프
while (curIdx !== minIdx) {
curIdx = minIdx;
//left는 curIdx * 2 + 1을 하는 이유는 right보다 작기 때문
let left = curIdx * 2 + 1;
//right는 curIdx * 2 + 2를 하는 이유는 left 보다 커야함
let right = curIdx * 2 + 2;
// minHeap before [ 1, 2, 4, 5, 3 ]
// minHeap after [ 2, 3, 4, 5 ]
//left가 heap 배열의 크기 미만이면서 heap[left]가 heap[minIdx]보다 미만일 경우
if (left < heap.length && heap[left] < heap[minIdx]) {
minIdx = left;
}
//right가 heap 배열의 크기 미만이면서 heap[right]가 heap[minIdx]보다 미만일 경우
if (right < heap.length && heap[right] < heap[minIdx]) {
minIdx = right;
}
//swap을 통해 더 작은 값이 뒤에있으면 앞의 값과 위치 교환함
//curIdx와 minIdx 위치 교환 heap 배열에서
swap(curIdx, minIdx, heap);
}
return heap;
}
// 아래 코드는 수정하지 마세요.
const binaryHeap = function (arr) {
//reduce로 새로운 배열을 반환
return arr.reduce((heap, item) => {
//insert 함수 호출
return insert(heap, item);
}, []);
};
const heapSort = function (arr) {
//minHeap에 binaryHeap 함수에 arr을 인자로 넣은 값을 저장
let minHeap = binaryHeap(arr);
console.log("minHeap before",minHeap)
//정답으로 반환할 sorted 배열 변수 선언
const sorted = [];
//minHeap의 배열 크기가 0을 초과하는 동안 계속 루프
while (minHeap.length > 0) {
//sorted에는 minHeap[0]을 삽입
//최소값을 먼저 계속 넣으면서 정렬
sorted.push(minHeap[0]);
//minHeap 변수에 removeRoot(minHeap)값을 저장
//removeRoot는 처음 원소와 마지막 원소 위치를 바꿈
console.log("sorted",sorted)
console.log("minHeap before", minHeap)
minHeap = removeRoot(minHeap);
console.log("minHeap after", minHeap)
}
return sorted;
};
let output = heapSort([5, 4, 3, 2, 1]);
console.log("output",output); // --> [1, 2, 3, 4, 5]
// output = heapSort([3, 1, 21]);
// console.log("output",output); // --> [1, 3, 21]
// output = heapSort([4, 10, 3, 5, 1]);
// console.log("output",output); // --> [1, 3, 4, 5, 10]
나는 코딩을 하면서 이해가 안되는 부분이 많아서 console.log로 찍어봤다.
다음은 console.log 결과값이다.
node 30_heapSort.js
before heap []
after heap [ 5 ]
before heap [ 5 ]
curIdx 1 pIdx 0
before while heap [ 5, 4 ]
after heap [ 4, 5 ]
before heap [ 4, 5 ]
curIdx 2 pIdx 0
before while heap [ 4, 5, 3 ]
after heap [ 3, 5, 4 ]
before heap [ 3, 5, 4 ]
curIdx 3 pIdx 1
before while heap [ 3, 5, 4, 2 ]
after heap [ 2, 3, 4, 5 ]
before heap [ 2, 3, 4, 5 ]
curIdx 4 pIdx 1
before while heap [ 2, 3, 4, 5, 1 ]
after heap [ 1, 2, 4, 5, 3 ]
minHeap before [ 1, 2, 4, 5, 3 ]
sorted [ 1 ]
minHeap before [ 1, 2, 4, 5, 3 ]
minHeap after [ 2, 3, 4, 5 ]
sorted [ 1, 2 ]
minHeap before [ 2, 3, 4, 5 ]
minHeap after [ 3, 5, 4 ]
sorted [ 1, 2, 3 ]
minHeap before [ 3, 5, 4 ]
minHeap after [ 4, 5 ]
sorted [ 1, 2, 3, 4 ]
minHeap before [ 4, 5 ]
minHeap after [ 5 ]
sorted [ 1, 2, 3, 4, 5 ]
minHeap before [ 5 ]
minHeap after []
output [ 1, 2, 3, 4, 5 ]
JavaScript Algorithm - largestRectangularArea (0) | 2023.02.16 |
---|---|
JavaScript Algorithm - rangeMinimum (0) | 2023.02.15 |
JavaScript Algorithm - binaryHeap(maxHeap) (0) | 2023.02.13 |
JavaScript Algorithm - robotPath2 (0) | 2023.02.10 |
JavaScript Algorithm - gossipProtocol (0) | 2023.02.09 |