[숙제] minHeap 구현, maxHeap -> minHeap , minHeap -> maxHeap
minHeap 구현
class MinHeap {
// 최소힙
arr = [];
#reheapUp(index) {
if (index > 0) {
const parentIndex = Math.floor((index - 1) / 2);
if (this.arr[index] < this.arr[parentIndex]) {
const tmp = this.arr[index];
this.arr[index] = this.arr[parentIndex];
this.arr[parentIndex] = tmp;
this.#reheapUp(parentIndex);
}
}
}
insert(value) {
const index = this.arr.length;
this.arr[index] = value; // 마지막에 값을 넣어준다.
this.#reheapUp(index);
}
#reHeapDown(index) {
const leftIndex = index * 2 + 1; // 왼쪽 Index
if (leftIndex < this.arr.length) {
const rightIndex = index * 2 + 2;
const smaller =
this.arr[leftIndex] < this.arr[rightIndex] ? leftIndex : rightIndex;
if (this.arr[index] > this.arr[smaller]) {
const temp = this.arr[index];
this.arr[index] = this.arr[smaller];
this.arr[smaller] = temp;
this.#reHeapDown(smaller);
}
}
}
remove() {
// root만 remove
if (this.arr.length === 0) {
return false;
}
if (this.arr.length === 1) {
// 마지막 하나 남으면 pop해서 리턴해주기
return this.arr.pop();
}
const root = this.arr[0];
this.arr[0] = this.arr.pop();
this.#reHeapDown(0);
return root;
}
sort() {
// 힙 정렬
const sortedArray = [];
while (this.arr.length > 0) {
sortedArray.push(this.remove());
}
return sortedArray;
}
search(value) {
for (let i = 0; i < this.arr.length; i++) {
if (this.arr[i] === value) {
return i;
}
}
return null;
}
// 특정값 수정
update(value, newValue) {
const index = this.search(value);
if (index === null) {
return false;
}
this.arr[index] = newValue;
for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) {
this.#heapify(i);
}
}
// 특정값 삭제
removeValue(value) {
const index = this.search(value);
if (index === null) {
return false;
}
// 특정값의 index를 splice를 이용하여 없애버린다.
this.arr.splice(index, 1);
for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) {
// 이렇게 했을때 힙이 깨질 수 있기 떄문에 heapify 해준다
this.#heapify(i);
}
}
transFormMaxHeap() {
for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) {
// i가 2부터 시작
// 이렇게 했을때 힙이 깨질 수 있기 떄문에 heapify 해준다
this.#maxHeapify(i);
}
return this.arr;
}
// 특정값을 수정하거나 특정값을 삭제하거나
#heapify(index) {
const leftIndex = index * 2 + 1; // 왼쪽 Index 78의 왼쪽 5: 23
const rightIndex = index * 2 + 2; // 오른쪽 6: undefined
const smaller =
(this.arr[leftIndex] || Number.MAX_SAFE_INTEGER) <
(this.arr[rightIndex] || Number.MAX_SAFE_INTEGER)
? leftIndex
: rightIndex;
if (this.arr[index] > this.arr[smaller]) {
const temp = this.arr[index];
this.arr[index] = this.arr[smaller];
this.arr[smaller] = temp;
this.#heapify(smaller);
}
}
#maxHeapify(index) {
const leftIndex = index * 2 + 1; // 왼쪽 Index
const rightIndex = index * 2 + 2;
const bigger =
(this.arr[leftIndex] || 0) > (this.arr[rightIndex] || 0)
? leftIndex
: rightIndex;
if (this.arr[index] < this.arr[bigger]) {
const temp = this.arr[index];
this.arr[index] = this.arr[bigger];
this.arr[bigger] = temp;
// 재귀 호출 해주어야 된다!
this.#maxHeapify(bigger);
}
}
}최소 힙 insert
const minheap = new MinHeap();
minheap.insert(78);
minheap.insert(56);
minheap.insert(45);
minheap.insert(32);
minheap.insert(23);
minheap.insert(19);
minheap.insert(8);
// 결과 [8, 32, 19, 78, 45, 56, 23]결과 그림

최소힙 remove
const minheap = new MinHeap();
minheap.insert(78);
minheap.insert(56);
minheap.insert(45);
minheap.insert(32);
minheap.insert(23);
minheap.insert(19);
minheap.insert(8);
minheap.remove();
minheap.remove();
minheap.remove();
minheap.remove();
minheap.remove();
minheap.remove();
// 8 , 32, 19, 78, 45 ,56, 23
// 19, 32, 23, 78, 45, 56
// 23, 32, 56, 78, 45
// 32, 45, 56, 78
// 45, 78, 56
// 56, 78
// 78최소힙 update
const minheap = new MinHeap();
minheap.insert(78);
minheap.insert(56);
minheap.insert(45);
minheap.insert(32);
minheap.insert(23);
minheap.insert(19);
minheap.insert(8);
minheap.update(32, 90);
// [8, 32, 19, 78, 45, 56, 23]
// 결과 -> [8, 45, 19, 78, 90, 56, 23]최소힙 removeValue
const minheap = new MinHeap();
minheap.insert(78);
minheap.insert(56);
minheap.insert(45);
minheap.insert(32);
minheap.insert(23);
minheap.insert(19);
minheap.insert(8);
minheap.removeValue(19);
// [8, 45, 19, 78, 90, 56, 23]
// 결과 -> [8, 45, 23, 90, 56, 78]최소힙 -> 최대힙
const minheap = new MinHeap();
minheap.insert(78);
minheap.insert(56);
minheap.insert(45);
minheap.insert(32);
minheap.insert(23);
minheap.insert(19);
minheap.insert(8);
console.log(minheap.transFormMaxHeap());
// [ 8, 32, 19, 78, 45, 56, 23 ]
// 결과 -> [78, 45, 56, 32, 8, 19, 23]최대힙 -> 최소힙
class MaxHeap {
arr = [];
#reheapUp(index) {
if (index > 0) {
const parentIndex = Math.floor((index - 1) / 2);
if (this.arr[index] > this.arr[parentIndex]) {
// 값 바꾸기
const tmp = this.arr[index];
this.arr[index] = this.arr[parentIndex];
this.arr[parentIndex] = tmp;
this.#reheapUp(parentIndex);
}
}
}
insert(value) {
const index = this.arr.length;
this.arr[index] = value; // 마지막에 값을 넣어준다.
this.#reheapUp(index);
}
#reHeapDown(index) {
const leftIndex = index * 2 + 1; // 왼쪽 Index
if (leftIndex < this.arr.length) {
// 만약에 왼쪽 인덱스가 총 배열의 길이보다 작은경우
const rightIndex = index * 2 + 2;
const bigger =
this.arr[leftIndex] > this.arr[rightIndex] ? leftIndex : rightIndex;
if (this.arr[index] < this.arr[bigger]) {
const temp = this.arr[index];
this.arr[index] = this.arr[bigger];
this.arr[bigger] = temp;
this.#reHeapDown(bigger);
}
}
}
remove() {
// root만 remove
if (this.arr.length === 0) {
return false;
}
if (this.arr.length === 1) {
// 마지막 하나 남으면 pop해서 리턴해주기
return this.arr.pop();
}
const root = this.arr[0];
this.arr[0] = this.arr.pop();
this.#reHeapDown(0);
return root;
}
sort() {
// 힙 정렬
const sortedArray = [];
while (this.arr.length > 0) {
sortedArray.push(this.remove());
}
return sortedArray;
}
search(value) {
for (let i = 0; i < this.arr.length; i++) {
if (this.arr[i] === value) {
return i;
}
}
return null;
}
// 특정값 수정
update(value, newValue) {
const index = this.search(value);
if (index === null) {
return false;
}
this.arr[index] = newValue;
for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) {
this.#heapify(i);
}
}
// 특정값 삭제
removeValue(value) {
const index = this.search(value);
if (index === null) {
return false;
}
// 특정값의 index를 splice를 이용하여 없애버린다.
this.arr.splice(index, 1);
for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) {
// 이렇게 했을때 힙이 깨질 수 있기 떄문에 heapify 해준다
this.#heapify(i);
}
}
transFromMinHeap() {
for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) {
// i가 2부터 시작
// 이렇게 했을때 힙이 깨질 수 있기 떄문에 heapify 해준다
this.#minHeapify(i);
}
return this.arr;
}
// 특정값을 수정하거나 특정값을 삭제하거나
#heapify(index) {
const leftIndex = index * 2 + 1; // 왼쪽 Index
const rightIndex = index * 2 + 2;
const bigger =
(this.arr[leftIndex] || 0) > (this.arr[rightIndex] || 0)
? leftIndex
: rightIndex;
if (this.arr[index] < this.arr[bigger]) {
const temp = this.arr[index];
this.arr[index] = this.arr[bigger];
this.arr[bigger] = temp;
this.#heapify(bigger);
}
}
// 특정값을 수정하거나 특정값을 삭제하거나
#minHeapify(index) {
const leftIndex = index * 2 + 1; // 왼쪽 Index 78의 왼쪽 5: 23
const rightIndex = index * 2 + 2; // 오른쪽 6: undefined
const smaller =
(this.arr[leftIndex] || Number.MAX_SAFE_INTEGER) <
(this.arr[rightIndex] || Number.MAX_SAFE_INTEGER)
? leftIndex
: rightIndex;
if (this.arr[index] > this.arr[smaller]) {
const temp = this.arr[index];
this.arr[index] = this.arr[smaller];
this.arr[smaller] = temp;
this.#minHeapify(smaller);
}
}
}
const heap = new MaxHeap();
heap.insert(8);
heap.insert(19);
heap.insert(23);
heap.insert(32);
heap.insert(45);
heap.insert(56);
heap.insert(78);
console.log(heap.transFormMinHeap());
// [78, 32, 56, 8, 23, 19, 45]
// -> 결과 [8, 23, 19, 32, 78, 56, 45]
질문1) maxheap(minheap) 코드 구현시 heapify 메서드에서 재귀호출 되어야 되지 않는가요?
강의에서는 heapify 메서드 구현시 재귀 호출 부분이 빠져있는것 같아서 질문 드립니다. 아니라면 죄송합니다.
#heapify(index) {
const leftIndex = index * 2 + 1; // 왼쪽 Index
const rightIndex = index * 2 + 2;
const bigger =
(this.arr[leftIndex] || 0) > (this.arr[rightIndex] || 0)
? leftIndex
: rightIndex;
if (this.arr[index] < this.arr[bigger]) {
const temp = this.arr[index];
this.arr[index] = this.arr[bigger];
this.arr[bigger] = temp;
// 여기 빠진것 같습니다!
this.#heapify(bigger);
}
}
Answer 1
1
heapify는 재귀 안 해도 됩니다. 그냥 for문 안에서 heapify 호출하면 끝입니다.
0
아하 그렇군요. 생각 해보니까 heapify는 이미 최대힙(또는 최소힙)을 보장하는 힙에 특정값을 update하거나 remove 하는 경우이기 때문에 그냥 for문 안에서 heapify 호출하면 되는거고
숙제중에서 제가 작성한 코드에서 최소힙 -> 최대힙으로 변경할때 minHeapify 메서드로 변환할때는 최소힙을 최대힙으로 다시 변경 하는거기 때문에 insert나 remove때처럼 재귀호출이 필요한거 제가 이해한게 맞을까요?
0
제가 이부분이 왜 궁금했었냐면요
class MinHeap {
// 최소힙
arr = [];
#reheapUp(index) {
if (index > 0) {
const parentIndex = Math.floor((index - 1) / 2);
if (this.arr[index] < this.arr[parentIndex]) {
const tmp = this.arr[index];
this.arr[index] = this.arr[parentIndex];
this.arr[parentIndex] = tmp;
this.#reheapUp(parentIndex);
}
}
}
insert(value) {
const index = this.arr.length;
this.arr[index] = value; // 마지막에 값을 넣어준다.
this.#reheapUp(index);
}
#reHeapDown(index) {
const leftIndex = index * 2 + 1; // 왼쪽 Index
if (leftIndex < this.arr.length) {
const rightIndex = index * 2 + 2;
const smaller =
this.arr[leftIndex] < this.arr[rightIndex] ? leftIndex : rightIndex;
if (this.arr[index] > this.arr[smaller]) {
const temp = this.arr[index];
this.arr[index] = this.arr[smaller];
this.arr[smaller] = temp;
this.#reHeapDown(smaller);
}
}
}
remove() {
// root만 remove
if (this.arr.length === 0) {
return false;
}
if (this.arr.length === 1) {
// 마지막 하나 남으면 pop해서 리턴해주기
return this.arr.pop();
}
const root = this.arr[0];
this.arr[0] = this.arr.pop();
this.#reHeapDown(0);
return root;
}
sort() {
// 힙 정렬
const sortedArray = [];
while (this.arr.length > 0) {
sortedArray.push(this.remove());
}
return sortedArray;
}
search(value) {
for (let i = 0; i < this.arr.length; i++) {
if (this.arr[i] === value) {
return i;
}
}
return null;
}
// 특정값 수정
update(value, newValue) {
const index = this.search(value);
if (index === null) {
return false;
}
this.arr[index] = newValue;
for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) {
this.#heapify(i);
}
}
// 특정값 삭제
removeValue(value) {
const index = this.search(value);
if (index === null) {
return false;
}
// 특정값의 index를 splice를 이용하여 없애버린다.
this.arr.splice(index, 1);
for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) {
// 이렇게 했을때 힙이 깨질 수 있기 떄문에 heapify 해준다
this.#heapify(i);
}
}
transFormMaxHeap() {
for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) {
// i가 2부터 시작
// 이렇게 했을때 힙이 깨질 수 있기 떄문에 heapify 해준다
this.#maxHeapify(i);
}
return this.arr;
}
// 특정값을 수정하거나 특정값을 삭제하거나
#heapify(index) {
const leftIndex = index * 2 + 1; // 왼쪽 Index 78의 왼쪽 5: 23
const rightIndex = index * 2 + 2; // 오른쪽 6: undefined
const smaller =
(this.arr[leftIndex] || Number.MAX_SAFE_INTEGER) <
(this.arr[rightIndex] || Number.MAX_SAFE_INTEGER)
? leftIndex
: rightIndex;
if (this.arr[index] > this.arr[smaller]) {
const temp = this.arr[index];
this.arr[index] = this.arr[smaller];
this.arr[smaller] = temp;
}
}
#maxHeapify(index) {
const leftIndex = index * 2 + 1; // 왼쪽 Index
const rightIndex = index * 2 + 2;
const bigger =
(this.arr[leftIndex] || 0) > (this.arr[rightIndex] || 0)
? leftIndex
: rightIndex;
if (this.arr[index] < this.arr[bigger]) {
const temp = this.arr[index];
this.arr[index] = this.arr[bigger];
this.arr[bigger] = temp;
// 재귀 호출 해주어야 된다!
this.#maxHeapify(bigger);
}
}
}
제일 첫번째 8을 90으로 update를 하게 됬을때
재귀호출 없을때
minheap.update(8, 90);
// [8, 32, 19, 78, 45, 56, 23]
// -> [19, 32, 90, 78, 45, 56, 23]재귀 호출을 넣었을때
minheap.update(8, 90);
// [8, 32, 19, 78, 45, 56, 23]
// -> [19, 32, 23, 78, 45, 56, 90]이러한 결과가 나오는데 재귀 호출을 넣었을때처럼 90이 마지막이 되어야 하는게 아닌가 해서 궁금해서 질문 드렸습니다. 결론적으로 제일 작은 수인 19만 맨위로 오고
오른쪽 자식이 90 -> 56, 90 -> 23 이렇게 되는건 딱히 상관 없는건가 해서요!

0
귀찮게 해드려서 죄송합니다. 또 질문하러 와버렸습니다 ㅠㅠ
class MaxHeap {
arr = [];
#reheapUp(index) {
if (index > 0) {
const parentIndex = Math.floor((index - 1) / 2);
if (this.arr[index] > this.arr[parentIndex]) {
// 값 바꾸기
const tmp = this.arr[index];
this.arr[index] = this.arr[parentIndex];
this.arr[parentIndex] = tmp;
this.#reheapUp(parentIndex);
}
}
}
insert(value) {
const index = this.arr.length;
this.arr[index] = value; // 마지막에 값을 넣어준다.
this.#reheapUp(index);
}
#reHeapDown(index) {
const leftIndex = index * 2 + 1; // 왼쪽 Index
if (leftIndex < this.arr.length) {
// 만약에 왼쪽 인덱스가 총 배열의 길이보다 작은경우
const rightIndex = index * 2 + 2;
const bigger =
this.arr[leftIndex] > this.arr[rightIndex] ? leftIndex : rightIndex;
if (this.arr[index] < this.arr[bigger]) {
const temp = this.arr[index];
this.arr[index] = this.arr[bigger];
this.arr[bigger] = temp;
this.#reHeapDown(bigger);
}
}
}
remove() {
// root만 remove
if (this.arr.length === 0) {
return false;
}
if (this.arr.length === 1) {
// 마지막 하나 남으면 pop해서 리턴해주기
return this.arr.pop();
}
const root = this.arr[0];
this.arr[0] = this.arr.pop();
this.#reHeapDown(0);
return root;
}
sort() {
// 힙 정렬
const sortedArray = [];
while (this.arr.length > 0) {
sortedArray.push(this.remove());
}
return sortedArray;
}
search(value) {
for (let i = 0; i < this.arr.length; i++) {
if (this.arr[i] === value) {
return i;
}
}
return null;
}
// 특정값 수정
update(value, newValue) {
const index = this.search(value);
if (index === null) {
return false;
}
this.arr[index] = newValue;
for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) {
this.#heapify(i);
}
}
// 특정값 삭제
removeValue(value) {
const index = this.search(value);
if (index === null) {
return false;
}
// 특정값의 index를 splice를 이용하여 없애버린다.
this.arr.splice(index, 1);
for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) {
// 이렇게 했을때 힙이 깨질 수 있기 떄문에 heapify 해준다
this.#heapify(i);
}
}
// 특정값을 수정하거나 특정값을 삭제하거나
#heapify(index) {
const leftIndex = index * 2 + 1; // 왼쪽 Index
const rightIndex = index * 2 + 2;
const bigger =
(this.arr[leftIndex] || 0) > (this.arr[rightIndex] || 0)
? leftIndex
: rightIndex;
if (this.arr[index] < this.arr[bigger]) {
const temp = this.arr[index];
this.arr[index] = this.arr[bigger];
this.arr[bigger] = temp;
}
}
}
const heap = new MaxHeap();
heap.insert(8);
heap.insert(19);
heap.insert(23);
heap.insert(32);
heap.insert(45);
heap.insert(56);
heap.insert(78);
heap.update(78, 1);
강의 코드 그대로 가져와서 update를 했는데 아래와 같은 결과가 나오는데
[ 78, 32, 56, 8, 23, 19, 45 ]
-> 결과 [ 56, 32, 1, 8, 23, 19, 45 ]
이것도 최대힙을 보장하지 않는거 아닌가 해서요.
제생각에는 결과가 [ 56, 32, 45, 8,23, 19, 1] 이렇게 되어야 되는게 아닌가 해서요.
2주차 개념#12 트리 순회
0
14
2
프론트엔드 학습 수준 문의
0
22
2
백준 사이트 서비스 종료
0
38
3
잠겨버린 사물함 시간초과 관련 질문입니다.
0
17
1
스택, 큐 연결리스트로 구현 과제 완료입니다!
0
93
1
heapify 안의 bigger 삼항연산자 질문
0
116
2
LinkedList로 스택, 큐 구현하기 숙제
0
123
1
linkedList prev와 tail 사용 후 o(1) 구현.
0
165
1
숙제 : LinkedList로 Stack, Queue 구현하기
0
177
1
연결리스트 숙제
0
239
1
한번에 이해 안가는 제가 비정상 일까요...?
0
234
1
우선순위 큐 질문이 있습니다!
0
154
1
최소힙 remove 구현하기
0
245
1
숙제 최소힙 만들기
0
152
1
숙제 length return 하기
0
194
1
숙제 : 같은 값을 넣은경우 에러 처리
0
181
1
영상 중간에 0:10 1:23초 수정에 따른 코드 최종본
1
143
1
숙제2 연결리스트를 이용하여 큐 구현하기
0
237
1
숙제1 LinkedList로 스택 구현하기
1
251
1
연결 리스트 구현 숙제 리뷰 부탁드려봅니다
1
345
2
let current = this.head 질문 있습니다!
0
251
1
퀴즈 답안
0
469
1
최소힙의 결과값과 최대힙->최소힙 결과값이 다른게 맞나요?
0
248
1
1주차 숙제에 대한 해답 코드는 따로 제공되지 않나요??
0
495
1

