堆排序的基本思想以及python实现

堆 排 序 \mathbf{堆排序}
  堆排序:只需要一个记录大小的辅助空间,每个待排序的记录仅占有一个存储空间。
  堆的定义:n个元素的序列 { k 1 , k 2 , . . . , k n } \{k_1,k_2,...,k_n\} {k1,k2,...,kn},当且仅当满足以下关系是,称为堆。
   { k i ⩽ k 2 i k i ⩽ k 2 i + 1 \begin{cases}k_i \leqslant k_{2i}\\ k_i \leqslant k_{2i+1}\end{cases} {kik2ikik2i+1 { k i ⩾ k 2 i k i ⩾ k 2 i + 1 \begin{cases}k_i \geqslant k_{2i}\\ k_i \geqslant k_{2i+1}\end{cases} {kik2ikik2i+1 i = 1 , 2 , . . . , ⌊ n 2 ⌋ i=1,2,...,\left\lfloor\dfrac{n}{2}\right\rfloor i=1,2,...,2n
  若将和此序列对应的二维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端节点的值均不大于(或不小于)其左右孩子节点的值。由此,若序列 { k 1 , k 2 , . . . , k n } \{k_1,k_2,...,k_n\} {k1,k2,...,kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。
  堆排序的主要思想:在输出堆顶的最小值(或最大值)之后,使得剩余的n-1个元素的序列又重建成一个堆,则得到n个元素中的次小值(或次大值)。如此反复执行,便能得到一个有序序列,此过程即为堆排序。
  实现堆排序需要解决两个问题:
  1)如何由一个无序序列建成一个堆?
  2)如何在输出堆顶元素之后,调整剩余元素成为一个新的堆?
  例题:假设给定的数组为[2,1,7,9,5,8],对其进行堆排序。(小顶堆)
  基本流程:
  1)首先对其进行堆调整。(无序序列建堆)
  在这里插入图片描述
  2)堆筛选
  在这里插入图片描述
  代码实现:

def HeapSort(H):
	# 从非叶节点开始调整
    i = (len(H)-1)//2
    while i > 0:
    	# 堆筛选函数
        HeapAdjust(H,i,len(H)-1)
        i -= 1
    # 用于存储堆排序的结果
    result = []
    # 输出H[1],并和尾结点交换,并删除。
    j = len(H)-1
    while j > 1:
    	# 添加H[1]到result中。
        result.append(H[1])
        # 交换位置
        H[1],H[j] = H[j],H[1]
        # 删除尾结点。
        H.pop()
        # 堆筛选
        HeapAdjust(H,1,j-1)
        j -= 1
    # 将H[1]添加到result中
    result.append(H[1])
    return result
def HeapAdjust(H,s,m):
	# 记录当前节点的值。
    rc = H[s]
    # 其左孩子节点
    j = 2 * s
    while j <= m:
    	# 如果j<m,则判断其左右孩子节点的值的大小,如果左孩子大于右孩子,则最小值为
    	# 右孩子
        if j < m and H[j] > H[j+1]:
            j += 1
        # 判断当前节点和左右孩子的最小值的大小
        # 如果根节点小于其左右孩子,则break。
        if rc < H[j]:
            break
        # 否则,将其左右孩子的最小值赋值给当前节点,继续调整被破坏的堆结构。
        H[s] = H[j]
        s = j
        j *= 2
    # 最后将当前节点的值,赋值给调整后的位置
    H[s] = rc

算法分析:
  时间复杂度:由于HeapSort函数的时间复杂度为O(n),HeapAdjust函数的时间复杂度为O(logn),所以整体的时间复杂度为O(nlogn)。
  空间复杂度:由于我们采用了一个result来存储最终的结果,所以其空间复杂度为O(n),但是我们也可以直接输出,不保存结果的话,其空间复杂度为O(1)。(大家有改进的方法的话,可以留言讨论。共勉!)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值