数据结构基础:python实现堆排序

本文介绍了堆的概念,包括大根堆和小根堆的定义。大根堆中每个节点的值大于或等于其子节点,小根堆则相反。堆排序的构建过程涉及逻辑上调整完全二叉树节点,通过交换节点和其最大子节点来维护堆性质。在排序阶段,通过堆顶元素与末尾元素交换并缩小堆的范围,最终实现排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

堆的概念:
堆是一种完全二叉树,就是除了最后一层之外的其他每一层都被完全填充,并且所有结点都保持向左对齐的树。就像码金字塔的砖块,必须从头到底,从左到右一个一个码,不能空缺。
堆有两种类型:大根堆,小根堆
大根堆:每个结点的值都大于或等于左右孩子结点
小根堆:每个结点的值都小于或等于左右孩子结点
大根堆:
大根堆
小根堆在这里插入图片描述
大根堆构建流程:

  1. 先依据构建一个完全二叉树
    此处并没有构造实际的二叉树,而是逻辑上:
import math
def print_tree(array):
    '''
        前空格元素间
    170
    237
    313
    4   01
    '''
    index = 1
    depth = math.ceil(math.log2(len(array))) # 因为补0了,不然应该是math.ceil(math.log2(len(array)+1))
    sep = '  '
    for i in range(depth):
        offset = 2 ** i
        print(sep * (2 ** (depth - i - 1) - 1), end='')
        line = array[index:index + offset]
        for j, x in enumerate(line):
            print("{:>{}}".format(x, len(sep)), end='')
            interval = 0 if i == 0 else 2 ** (depth - i) - 1
            if j < len(line) - 1:
                print(sep * interval, end='')
        index += offset
        print()
# Heap Sort
# 为了和编码对应,增加一个无用的0在首位
origin = [0, 30, 20, 80, 40, 50, 10, 60, 70, 90]
total = len(origin) - 1  # 初始待排序元素个数,即n
print_tree(origin)
打印结果:
  				30
      20              80
  40      50      10      60
70  90
  1. 调整完全二叉树中的堆节点
    1)度数为2的结点A,如果它的左右孩子结点的最大值比它大的,将这个最大值和该结点交换
    2)度数为1的结点A,如果它的左孩子的值大于它,则交换
    3)如果结点A被交换到新的位置,还需要和其孩子结点重复上面的过程
def heap_adjust(n, i, array: list):
    '''
    调整当前结点(核心算法)
    调整的结点的起点在n//2,保证所有调整的结点都有孩子结点
    :param n: 待比较数个数
    :param i: 当前结点的下标
    :param array: 待排序数据
    :return: None
    '''
    while 2 * i <= n:
        # 孩子结点判断 2i为左孩子,2i+1为右孩子
        lchile_index = 2 * i
        max_child_index = lchile_index  # n=2i
        if n > lchile_index and array[lchile_index + 1] > array[lchile_index]:  # n>2i说明还有右孩子
            max_child_index = lchile_index + 1  # n=2i+1
        # 和子树的根结点比较
        if array[max_child_index] > array[i]:
            array[i], array[max_child_index] = array[max_child_index], array[i]
            i = max_child_index  # 当前节点调整后,被交换的节点max_child_index所在的子堆,需要判断是否还需要调整
        else:
            break
       

3.构建大根堆:

def max_heap(total,array:list):
    for i in range(total//2,0,-1):
        heap_adjust(total,i,array)
    return array
print_tree(max_heap(total,origin))
结果:    90
      70              80
  40      50      10      60
20  30

构建完大根堆后,开始排序:

  1. 每次都要让堆顶的元素和最后一个结点交换,然后排除最后一个元素,形成一个新的被破坏的堆。
  2. 让它重新调整,调整后,堆顶一定是最大的元素。
  3. 再次重复第1、2步直至剩余一个元素
def sort(total, array:list):
    while total > 1:
        array[1], array[total] = array[total], array[1]
        print_tree(origin)# 堆顶和最后一个结点交换
        total -= 1
        if total == 2 and array[total] >= array[total-1]:
            break
        heap_adjust(total,1,array)
        print_tree(origin)
    return array
print_tree(sort(total,origin))
结果:   10
      20              30
  40      50      60      70
80  90
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值