堆排序与python实现 2023-09-19(未允禁转)

2023-09-18  本文已影响0人  9_SooHyun

调用关系:

                       heap_sort
                 /                  |
build_max_heap_by_down_adjust       |
              \                     |
                maxheap_down_adjust              

堆排序python实现:

def heap_sort(array: list[int]) -> None:
    """
    原地堆排序 (大顶堆实现的从小到大排序)
    """

    # egde case
    if len(array) <= 1:
        return

    # 1. 建堆. 建堆有2种思路:down_adjust 和 up_adjust。详见下文说明
    build_max_heap_by_down_adjust(array)
    # build_max_heap_by_up_adjust(array)

    # 2. loop to sort: 将array首尾换位置,最大值到最后,然后再maxheap_down_adjust
    for i in range(len(array) - 1, 0, -1):
        array[i], array[0] = array[0], array[i]
        maxheap_down_adjust(array, 0, i - 1)

    return

def build_max_heap_by_down_adjust(array: list[int]) -> None:
    # 构建大顶堆 by_down_adjust
    # down_adjust从最后一个非叶子结点起(也可以从叶子结点起,但没必要,因为叶子本身已经是合法的堆结构),
    # 倒序地通过maxheap_down_adjust构建每个子大顶堆
    lenth = len(array)
    for i in range(lenth // 2 - 1, -1, -1):
        # i as maxheap root_index
        maxheap_down_adjust(array, i, lenth - 1)

    print(f"heap built as: {array}")
    return

def maxheap_down_adjust(array: list[int], root_index: int, end_index: int) -> None:
    """
    maxheap_down_adjust 以root_index为根的一个大顶堆的向下调整。
    【前提条件是root的左右结点已经是大顶堆根,这样才能做到root只需要关注自己的左右结点】

    :param array: 待排序的数组,可通过下标推断parent node和child node
    :param root_index: 大顶堆根的index
    :param end_index: 推断parent node和child node时,最后一个合法index
    :return: None
    """

    # down_adjust过程:
    # 1. if 树根(array[root_index])的左子结点存在,且左子结点值 > 树根,将树根与左子结点进行值交换, and build_max_heap(array, left_child_index)
    # 2. if 树根(array[root_index])的右子结点存在,且右子结点值 > 树根,将树根与右子结点进行值交换, and build_max_heap(array, right_child_index)
    if root_index > end_index:
        raise ValueError(f"err: root_index({root_index}) > end_index({end_index})")

    left_child_index, right_child_index = 2 * root_index + 1, 2 * root_index + 2

    if left_child_index <= end_index:
        left_child_value = array[left_child_index]
        if left_child_value > array[root_index]:
            # swap value of root and left_child
            array[left_child_index], array[root_index] = array[root_index], array[left_child_index]
            # maxheap_down_adjust left_child recursively
            maxheap_down_adjust(array, left_child_index, end_index)

    if right_child_index <= end_index:
        right_child_value = array[right_child_index]
        if right_child_value > array[root_index]:
            # swap value of root and right_child
            array[root_index], array[right_child_index] = array[right_child_index], array[root_index]
            # maxheap_down_adjust right_child recursively
            maxheap_down_adjust(array, right_child_index, end_index)

    return

def build_max_heap_by_up_adjust(array: list[int]) -> None:
    # 构建大顶堆 by_up_adjust
    # up_adjust从首个结点起,
    # 顺序地对每个节点使用maxheap_up_adjust进行堆调整
    lenth = len(array)
    for i in range(lenth):
        maxheap_up_adjust(array, i)
    print(f"heap built as: {array}")
    return

def maxheap_up_adjust(array: list[int], bottom_index: int) -> None:
    child_index = bottom_index
    parent_index = (child_index - 1) // 2

    if parent_index >= 0 and array[child_index] > array[parent_index]:
        # swap parent and child
        array[child_index], array[parent_index] = array[parent_index], array[child_index]
        # 继续以 parent_index 为 bottom 节点进行向上调整
        maxheap_up_adjust(array, parent_index)

test_list = [134, 5, 565, 35, 676, 3, 2, 1, 4, 5]
heap_sort(test_list)
print(test_list)

down_adjust和up_adjust

down_adjust(向下调整):

down_adjust将调整起点视为堆顶元素,从堆顶开始向下调整堆结构,以维护堆的性质(大顶堆或小顶堆)。这个操作通常在堆顶元素被移除或替换时使用,例如在堆排序算法中,将堆顶元素与最后一个元素交换后,需要通过down_adjust重新调整堆结构。

down_adjust的具体步骤如下:

up_adjust(向上调整):

up_adjust将调整起点视为堆底元素,从堆底开始向上调整堆结构,以维护堆的性质(大顶堆或小顶堆)。这个操作通常在向堆中插入新元素时使用,例如在构建堆或实现优先级队列时,需要通过up_adjust调整堆结构。

up_adjust的具体步骤如下:

上一篇 下一篇

猜你喜欢

热点阅读