Skip to content

Heap Sort Algorithm

Published: at 오전 03:06

Table of contents

Open Table of contents

Python 코드

import sys

input = sys.stdin.readline

sys.setrecursionlimit(10**9)


def get_heap_sorted_list(unsorted_list, heap_type):
    """
    heap 정렬을 이용하여 리스트를 정렬한다.
    >>> get_heap_sorted_list([31, 30, 23, 2, 33, 61, 87, 58, 53, 32, 68, 29, 38, 34, 66, 42, 8, 21, 125, 341, 221, 648, 62, 1, 921], "max")
    [1, 2, 8, 21, 23, 29, 30, 31, 32, 33, 34, 38, 42, 53, 58, 61, 62, 66, 68, 87, 125, 221, 341, 648, 921]

    >>> get_heap_sorted_list([31, 30, 23, 2, 33, 61, 87, 58, 53, 32, 68, 29, 38, 34, 66, 42, 8, 21, 125, 341, 221, 648, 62, 1, 921], "min")
    [921, 648, 341, 221, 125, 87, 68, 66, 62, 61, 58, 53, 42, 38, 34, 33, 32, 31, 30, 29, 23, 21, 8, 2, 1]
    """

    sorted_list = [*unsorted_list]
    list_len = len(sorted_list)

    def heapify(root_idx, heap_size):
        next_idx = root_idx
        left_child_idx = 2 * root_idx + 1
        right_child_idx = 2 * root_idx + 2

        def is_next_idx_updatable_to_left_child_idx():
            if left_child_idx >= heap_size:
                return False
            return True

        def is_next_idx_updatable_to_right_child_idx():
            if right_child_idx >= heap_size:
                return False
            return True

        def update_next_idx_to_left_child_idx():
            nonlocal next_idx
            if is_next_idx_updatable_to_left_child_idx() == False:
                return
            if heap_type == "max":
                # 왼쪽 sub-tree의 루트가 지금 루트보다 크면, 가장 큰 값의 인덱스 업데이트.
                if sorted_list[left_child_idx] > sorted_list[next_idx]:
                    next_idx = left_child_idx
            elif heap_type == "min":
                # 왼쪽 sub-tree의 루트가 지금 루트보다 작으면, 가장 작은 값의 인덱스 업데이트.
                if sorted_list[left_child_idx] < sorted_list[next_idx]:
                    next_idx = left_child_idx

        def update_next_idx_to_right_child_idx():
            nonlocal next_idx
            if is_next_idx_updatable_to_right_child_idx() == False:
                return
            if heap_type == "max":
                # 오른쪽 sub-tree의 루트가 지금 루트보다 크면, 가장 큰 값의 인덱스 업데이트.
                if sorted_list[right_child_idx] > sorted_list[next_idx]:
                    next_idx = right_child_idx
            elif heap_type == "min":
                # 오른쪽 sub-tree의 루트가 지금 루트보다 작으면, 가장 작은 값의 인덱스 업데이트.
                if sorted_list[right_child_idx] < sorted_list[next_idx]:
                    next_idx = right_child_idx

        update_next_idx_to_left_child_idx()
        update_next_idx_to_right_child_idx()
        # 다음 인덱스가 루트의 인덱스와 같으면, 종료한다.
        # 더 이상, sub-tree에 대해 heapify를 호출할 필요가 없다.
        if next_idx == root_idx:
            return

        sorted_list[next_idx], sorted_list[root_idx] = (
            sorted_list[root_idx],
            sorted_list[next_idx],
        )
        heapify(next_idx, heap_size)

    # 힙 트리를 구성한다.
    # 힙 트리의 leap node는 자식 노드가 없으므로, heapify를 호출할 필요가 없다.
    # 그래서, 힙 트리의 non-leap node부터 heapify를 호출한다. (list_len // 2 - 1)
    # 작은 힙 트리부터 heapify를 호출하여, 점점 위로 올라간다.
    for i in range(list_len // 2 - 1, -1, -1):
        heapify(i, list_len)
    # 힙 트리의 root node와 마지막 node를 교환한다.
    # 가장 작거나 큰 값이 마지막 node에 위치하게 된다.
    # 그러면 마지막으로 교환된 node는 정렬이 완료된 것이므로, heapify를 호출할 필요가 없다.
    # 그래서, 힙 트리의 root node부터 heapify를 호출한다.
    # 대신, 정렬돼서 미리 빼 놓은 마지막 node는 heapify의 범위에서 제외한다.

    for i in range(list_len - 1, 0, -1):
        sorted_list[0], sorted_list[i] = sorted_list[i], sorted_list[0]
        heapify(0, i)
    return sorted_list


if __name__ == "__main__":
    heap_type = input().rstrip()
    unsorted_list = list(map(int, input().rstrip().split(",")))
    print(get_heap_sorted_list(unsorted_list, heap_type))

How to Run

python version: 3.11.6

Run main.py

pip install pipenv
pipenv --python 3.11.6
pipenv run python3 main.py

Input

min
31, 30, 23, 2, 33, 61, 87, 58, 53, 32, 68, 29, 38, 34, 66, 42, 8, 21, 125, 341, 221, 648, 62, 1, 921

Output

[921, 648, 341, 221, 125, 87, 68, 66, 62, 61, 58, 53, 42, 38, 34, 33, 32, 31, 30, 29, 23, 21, 8, 2, 1]

Run doctest

pipenv run python3 -m doctest -v main.py

Output

Trying:
    get_heap_sorted_list([31, 30, 23, 2, 33, 61, 87, 58, 53, 32, 68, 29, 38, 34, 66, 42, 8, 21, 125, 341, 221, 648, 62, 1, 921], "max")
Expecting:
    [1, 2, 8, 21, 23, 29, 30, 31, 32, 33, 34, 38, 42, 53, 58, 61, 62, 66, 68, 87, 125, 221, 341, 648, 921]
ok
Trying:
    get_heap_sorted_list([31, 30, 23, 2, 33, 61, 87, 58, 53, 32, 68, 29, 38, 34, 66, 42, 8, 21, 125, 341, 221, 648, 62, 1, 921], "min")
Expecting:
    [921, 648, 341, 221, 125, 87, 68, 66, 62, 61, 58, 53, 42, 38, 34, 33, 32, 31, 30, 29, 23, 21, 8, 2, 1]
ok
1 items had no tests:
    main
1 items passed all tests:
   2 tests in main.get_heap_sorted_list
2 tests in 2 items.
2 passed and 0 failed.
Test passed.

Execution Image