Idealim
article thumbnail
Published 2021. 10. 19. 10:13
[Algorithm] 힙 정렬 CS/Algorithm

/* 본 게시물은 참고자료를 토대로 작성되었습니다. */

/* 본 글은 개인적으로 공부한 내용을 정리한 글이므로 오류가 있을 수 있습니다. */

1. 참고 자료

[BoostCourse] 자바로 구현하고 배우는 자료구조 - 힙 정렬 : https://www.boostcourse.org/cs204


2. 힙 정렬

힙 규칙에 맞게 숫자의 순서를 맞추는 과정을 힙 정렬 알고리즘이라고 한다. *힙에 대해 자세히 알고 싶다면 다음 을 확인하면 된다. 

만약 데이터가 힙 규칙에 따라 있다면, trickleDown을 반복하면 숫자들이 정렬된다. 이때 최대힙 이면 오름차순으로, 최소힙이면 내림차순으로 정렬된다. 

코드는 다음과 같다.

<kotlin />
fun heapSort(): E{ val removeVal = array[1] as E if (array[1] == null){ throw NoSuchElementException() } swap(1,size--) -> root 와 swap 하고 root값(최대값)을 힙에서 제외 trickleDown(1) return removeVal }

 

전체 코드는 다음과 같다.

<kotlin />
class Heap<E>(capacity: Int = DEFAULT_CAPACITY){ var array = arrayOfNulls<Any>(capacity) var size = 0 // 받은 인덱스의 부모 노드 인덱스를 반환 private fun getParent(index: Int): Int { return index / 2 } // 받은 인덱스의 왼쪽 자식 노드 인덱스를 반환 private fun getLeftChild(index: Int): Int { return index * 2 } // 받은 인덱스의 오른쪽 자식 노드 인덱스를 반환 private fun getRightChild(index: Int): Int { return index * 2 + 1 } companion object { private const val DEFAULT_CAPACITY = 10 // 기본 용량 } // 용량 초과 시 용량 증가하는 함수 private fun resize(newCapacity: Int) { // 새로 만들 배열 val newArray = arrayOfNulls<Any>(newCapacity) // 새 배열에 기존에 있던 배열의 요소들 복사 for (i in 1..size) { newArray[i] = array[i] } array = newArray } fun add(value: E) { // 용량이 꽉 차있을 경우 용적을 두 배로 늘려준다. if (size + 1 == array.size) { resize(array.size * 2) } array[size+1] = value trickleUp(size + 1, value as Comparable<E>) // 가장 마지막에 추가 되는 위치와 넣을 값(타겟)을 넘겨줌 size++ // 정상적으로 재배치가 끝나면 사이즈를 증가 } private fun swap(from: Int, to: Int) { val tmp= array[from] as E array[from] = array[to] array[to] = tmp } private fun trickleUp(idx: Int, target: Comparable<E>){ val parent = getParent(idx) val parentVal = array[parent] as E if (idx <= 1){ return } if (target > parentVal){ swap(idx, parent) trickleUp(parent, target) } } fun heapSort(): E{ val removeVal = array[1] as E if (array[1] == null){ throw NoSuchElementException() } swap(1,size--) -> root 와 swap 하고 root값(최대값)을 힙에서 제외 trickleDown(1) return removeVal } private fun trickleDown(parent: Int){ val left = getLeftChild(parent) val right = getRightChild(parent) // 마지막 노드가 왼쪽 자식 밖에 없을 때 왼쪽 자식이 클 때 if (left == size && (array[parent] as Comparable<E>) < (array[left] as E)){ swap(parent,left) return } // 마지막에 오른쪽 자식이 클 때 if (right == size && (array[parent] as Comparable<E>) > (array[left] as E)){ swap(parent,right) return } // 마지막에 부모가 클 때 (밑에 자식이 없을 때) if (left > size || right > size) return // 왼쪽 자식이 클 때 if (array[left] as Comparable<E> > array[right] as E && array[parent] as Comparable<E> < array[left] as E) { swap(parent, left) trickleDown(left) } // 오른쪽 자식이 클 때 else if (array[parent] as Comparable<E> < array[right] as E){ swap(parent, right) trickleDown(right) } } }
반응형
profile

Idealim

@Idealim

읽어주셔서 감사합니다. 잘못된 내용이 있으면 언제든 댓글로 피드백 부탁드립니다.