fun main() {
    val arr = intArrayOf(3, 2, 5, 1, 4, 6)
    heapSort(arr)
    println(arr.contentToString())
}

fun heapSort(arr: IntArray) {
    val n = arr.size

    // 초기 힙 구성: 가장 마지막 부모 노드부터 시작하여 최대 힙 구성
    for (i in n / 2 - 1 downTo 0) {
        heapify(arr, n, i)
    }

    // 요소를 하나씩 제거하면서 힙을 재구성
    for (i in n - 1 downTo 1) {
        // 최대 힙의 루트(가장 큰 값)를 배열의 마지막 요소와 교환
        arr[0] = arr[i].also { arr[i] = arr[0] }
        // 힙 크기를 줄이고, 루트 노드를 재구성하여 최대 힙 유지
        heapify(arr, i, 0)
    }
}

// i를 루트로 하는 부분 힙을 최대 힙으로 구성하는 함수
fun heapify(arr: IntArray, n: Int, i: Int) {
    var largest = i         // 최대값을 가진 노드의 인덱스 초기화
    val left = 2 * i + 1    // 왼쪽 자식 인덱스
    val right = 2 * i + 2   // 오른쪽 자식 인덱스

    // 왼쪽 자식이 현재 최대값보다 크면, 최대값 인덱스 업데이트
    if (left < n && arr[left] > arr[largest]) {
        largest = left
    }

    // 오른쪽 자식이 현재 최대값보다 크면, 최대값 인덱스 업데이트
    if (right < n && arr[right] > arr[largest]) {
        largest = right
    }

    // 최대값이 루트가 아니라면, 루트와 최대값 교체
    if (largest != i) {
        arr[i] = arr[largest].also { arr[largest] = arr[i] }
        // 변경된 노드를 루트로 하는 부분 힙 재구성
        heapify(arr, n, largest)
    }
}