算法刷题打卡第46天:排序数组---堆排序

排序数组

难度:中等

给你一个整数数组 nums,请你将该数组升序排列。

示例 1:

输入:nums = [5,2,3,1]
输出:[1,2,3,5]

示例 2:

输入:nums = [5,1,1,2,0,0]
输出:[0,0,1,1,2,5]

堆排序

思路:
许多应用程序都需要处理有序的元素,但不一定要求他们全部有序,或者不一定要一次就将他们排序,很多时候,我们每次只需要操作数据中的最大元素(最小元素),那么有一种基于二又堆的数据结构可以提供支持。

所谓二叉堆,是一个完全二叉树的结构,同时满足堆的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。在一个二又堆中,根节点总是最大(或者最小)节点,这样堆我们称之为最大(小)堆。

堆排序算法就是抓住了这一特点,每次都取堆顶的元素,然后将剩余的元素重新调整为最大(最小)堆,依次类推,最终得到排序的序列。

堆排序初始时把要排序的数的序列看作是一棵顺序存储的二叉树,调整它们的存储序,使之成为一个堆,这时堆的根节点的数最大。然后将根节点与堆的最后一个节点交换。然后对前面(n-1)个数重新调整使之成为堆。依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。从算法描述来看,堆排序需要两个过程,一是建立堆,二是堆顶与堆的最后一个元素交换位置。所以堆排序有两个函数组成。一是建堆的渗透函数,二是反复调用渗透函数实现排序的函数。

完全二叉树特性:
在这里插入图片描述

  • 推论1: 对于位置为K的结点 左子结点=2k+1 右子结点=2(k+1)验证: C:2 22+1=52(2+1)=6
  • 推论2: 最后一个非叶节点的位置为 (N/2)-1,N为数组长度。验证: 数组长度为6,(6/2)-1=2

样例如下:
请添加图片描述

时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn),第一次构建最大堆的时候时间复杂度为 O ( n ) O(n) O(n),后续弹出堆顶元素后重建堆过程的时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn),最终时间复杂度为: O ( n ) + O ( n l o g n ) = O ( n l o g n ) O(n) + O(nlogn) = O(nlogn) O(n)+O(nlogn)=O(nlogn)
空间复杂度: O ( 1 ) O(1) O(1),原地排序算法。

class Solution:
    def adjustHeap(self, nums, index, length):
        l, r = 2*index+1, 2*(index+1)
        maxIndex = index
        if l < length and nums[l] > nums[maxIndex]:
            maxIndex = l
        if r < length and nums[r] > nums[maxIndex]:
            maxIndex = r
        if maxIndex != index:
            nums[index], nums[maxIndex] = nums[maxIndex], nums[index]
            self.adjustHeap(nums, maxIndex, length)

    def sortArray(self, nums: List[int]) -> List[int]:
        length = len(nums)
        # 构建一个最大堆
        for i in range(int(length/2-1), -1, -1):
            self.adjustHeap(nums, i, length)
        # 堆排序
        while length > 1:
            nums[0], nums[length-1] = nums[length-1], nums[0]
            length -= 1
            self.adjustHeap(nums, i, length)
        return nums

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/sort-an-array

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏秃然

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值