堆排序

一、堆排序

堆实际上就是一个完全二叉堆,它分为两个类型:

1、最大堆:任意的父节点的值都大于等于它左右孩子节点的值。

2、最小堆:任意的父节点的值都小于等于它左右孩子节点的值。

二叉堆的根节点叫做堆顶。

根据最大堆和最小堆的特点,可以得出最大堆的顶点是整个堆中的最大元素,最小堆中的顶点是整个堆中最小的元素。

最大堆满足:parent >= 2*parent+1 (左节点) && parent >= 2*parent+2(右节点) 

最小堆满足:parent <= 2*parent+1(左节点)&& parent <= 2*parent+2 (右节点)

最大堆:参照下图大顶堆

索引:0parent2342*parent+12*parent+2
数列:9683453

 

最小堆:参照下图小顶堆

索引:0parent22*parent+12*parent+25
数列:465798

大顶å åå°é¡¶å 

堆的自我调整:如何从一个无序的序列转换成上述的最大堆和最小堆的过程。

下面转自:图解排序算法

  • 给定一个无序列表结构如下:将其转换成最大堆:(一般升序采用最大堆,降序采用最小堆)

  • 从最后一个非叶子节点开始(就是图中红色的6),从左到右,从上到下依次进行调整,调整的规则就是按照:最大堆满足的特点

最大堆满足:parent >= 2*parent+1 (左节点) && parent >= 2*parent+2(右节点) 

  • 然后继续找到第二个非叶子节点4,选择最大的元素进行交换,因此9和4进行调换,有下面结果

  • 4和9交换后,会导致下面的4,5,6不满足最大堆的条件,因此继续按照规则进行调整;将4和6进行交换;

此时就可以将最初无序的列表变成一个最大堆结构:

再将堆顶元素与末尾元素进行交换,使得末尾元素最大,然后继续调整堆,再将堆顶元素与末尾元素进行交换,反复重复这个操作;

  • 将堆顶元素9与末尾元素4进行交换,就把9从树中踢出。

  • 重新按照最大堆的定义对结构进行调整;

  • 再将顶点元素8与末尾元素5进行交换,就得到第二大元素8

  • 继续重复上述操作,最后得到一个有序序列

代码实现:题目来源于leetcode:215

在未排序的数组中找到第k个最大的元素,注意,你需要找的是数组排序后的第k个最大的元素,而不是第k个
不同的元素。
例如:输入:[3,2,1,5,6,4] 和 k=2
           输出:5

# 利用堆排序进行求解
class Solution(object):
    def findKthLargest(self,nums,k):
        # 堆排序
        self._k = len(nums)-k
        return self.heapsort(nums)

    # 执行堆排序
    def heapsort(self,nums):
        self.build_heap(nums)
        for i in range(len(nums)-1,self._k-1,-1):
            nums[i],nums[0] = nums[0],nums[i]
            # 这里要排除最后一个元素
            self.max_heapify(nums,0,i)
        return nums[self._k]

    def build_heap(self,nums):
        length = len(nums)
        for i in range(((length-1) // 2),-1,-1):
            # 从最后一个节点的父节点开始向上调整
            self.max_heapify(nums,i,length)

    def max_heapify(self,nums,i,length):
        left = i*2 + 1
        right = i*2 + 2
        if left < length and nums[left] > nums[i]:
            largest = left
        else:
            largest = i
        if right < length and nums[right] > nums[largest]:
            largest = right
        if largest != i:
            nums[i],nums[largest] = nums[largest],nums[i]
            # 子树也需要按照最大堆规则进行调整
            self.max_heapify(nums,largest,length)

if __name__ == '__main__':
    s = Solution()
    print(s.findKthLargest([3,2,3,1,2,4,5,5,6],4))

另一种简洁做法:

class Solution:
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        return heapq.nlargest(k, nums)[-1]
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

kaichu2

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

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

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

打赏作者

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

抵扣说明:

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

余额充值