python实现堆的基本操作及堆相关练习

堆(heap)

又被为优先队列(priority queue)。尽管名为优先队列,但堆并不是队列。回忆一下,在队列中,我们可以进行的限定操作是dequeue和enqueue。

dequeue是按照进入队列的先后顺序来取出元素。而在堆中,我们不是按照元素进入队列的先后顺序取出元素的,而是按照元素的优先级取出元素。

性质

堆的实现通过构造二叉堆(binary heap),实为二叉树的一种;由于其应用的普遍性,当不加限定时,均指该数据结构的这种实现。这种数据结构具有以下性质。

  • 任意节点小于(或大于)它的所有后裔,最小元(或最大元)在堆的根上(堆序性)。
  • 堆总是一棵完全树。即除了最底层,其他层的节点都被元素填满,且最底层尽可能地从左到右填入。

实现

  • 堆的主要操作是插入和删除最小元素(元素值本身为优先级键值,小元素享有高优先级)
  • 在插入或者删除操作之后,我们必须保持该实现应有的性质: 1. 完全二叉树 2. 每个节点值都小于或等于它的子节点

上浮(Promotion)

情境: 子节点的键值变为比父节点的键值大;如下面添加字节点

消除这种违反项: 

  • 交换子节点的键和父节点的键 
  • 重复这个过程直到堆的顺序恢复正常

堆的添加:

下沉(Demotion) 

情境:父节点的键值变得比子节点(一个或者2个) 的键值还小 ,如下面删除了根节点后拿了个小子节点补充上来的情况

消除这种违反项:

  • 把父节点的键值和比它大的子节点的键值做交换
  • 重复这个操作直到堆的顺序恢复正常

删除最大值

参考博客:python数据结构之堆(heap) - kumata - 博客园

python实现常见堆操作

# 堆化实现 heapify(x)
def heapify(heap, n,index):
    # Transform list into a heap, in-place,index开始标志
    #n = len(heap)
    left = index * 2 + 1  # 左孩子下标
    while left < n:
        largest = left+1 if left + 1 < n and heap[left + 1] > heap[left] else left
        largest = largest if heap[largest] > heap[index] else index
        if largest == index:
            break
        heap[index], heap[largest] = heap[largest], heap[index]
        index = largest
        left = index * 2 + 1

def heapinsert(heap, index):
    f=int((index-1)>>1)
    while heap[index]>heap[f]:
        heap[index],heap[f] =heap[f] ,heap[index]
        index=f
def heapSort(arr):
    n = len(arr)
    # Build a maxheap.
    for i in range(n, -1, -1):
        heapify(arr, n, i)
    for i in range(n - 1, 0, -1):
        arr[i], arr[0] = arr[0], arr[i]  # 交换
        heapify(arr, i, 0)
if __name__ == '__main__':
    arr = [12, 11, 13, 5, 6, 7]
    heapSort(arr)
    n = len(arr)
    # for i in range(0, n, 1):
    #     heapinsert(arr, i)
    print("排序后")
    for i in range(n):
        print("%d" % arr[i])

python内置方法创建堆有两种方式,heappush()和heapify()

heaqp模块提供了堆队列算法的实现,也称为优先级队列算法。
要创建堆,请使用初始化为[]的列表,或者可以通过函数heapify()将填充列表转换为堆。 提供以下功能: heapq.heappush(堆,项目) 将值项推入堆中,保持堆不变。
heapq.heapify(x) 在线性时间内将列表x转换为堆。 heapq.heappop(堆) 弹出并返回堆中的最小项,保持堆不变。如果堆是空的,则引发IndexError。 

'''
heaqp模块提供了堆队列算法的实现,也称为优先级队列算法。
要创建堆,请使用初始化为[]的列表,或者可以通过函数heapify()将填充列表转换为堆。
提供以下功能:
heapq.heappush(堆,项目)
将值项推入堆中,保持堆不变。
heapq.heapify(x)
在线性时间内将列表x转换为堆。
heapq.heappop(堆)
弹出并返回堆中的最小项,保持堆不变。如果堆是空的,则引发IndexError。
'''
import heapq 

#1 heappush生成堆+ heappop把堆从小到大pop出来 
heap = []
data = [1,3,5,7,9,2,4,6,8,0]
for i in data:
    heapq.heappush(heap,i)
print(heap)

lis = []
while heap:
    lis.append(heapq.heappop(heap))
print(lis)

#2 heapify生成堆+ heappop把堆从小到大pop出来 
data2 = [1,5,3,2,9,5]
heapq.heapify(data2)
print(data2)

lis2 = []
while data2:
    lis2.append(heapq.heappop(data2))
print(lis2)

#输出结果
[0, 1, 2, 6, 3, 5, 4, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 5, 9, 5]
[1, 2, 3, 5, 5, 9]

 215. 数组中的第K个最大元素

难度中等950

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:输入: [3,2,1,5,6,4] 和 k = 2 输出: 5

示例 2:输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 输出: 4

class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        nums.sort(reverse=True)
        return nums[k-1]

方法二:堆排序

方法三快速选择

#215. 数组中的第K个最大元素
import heapq
def findKthLargest(nums, k: int) :
    # nums.sort(reverse=True)
    # return nums[k-1]
    heap=[]
    for i in nums:
        heapq.heappush(heap, i*-1)
    print(heap)
    while k>1:
        k=k-1
        heapq.heappop(heap)
        print(heap)
    return heap[0]*-1
nums=[3,2,1,1,5,6,4]
k=2
# nums=[3,2,3,1,2,4,5,5,6]
# k=4
print(findKthLargest(nums, k))

692. 前K个高频单词

难度中等222

给一非空的单词列表,返回前 个出现次数最多的单词。

返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率,按字母顺序排序。

示例 1:

输入: ["i", "love", "leetcode", "i", "love", "coding"], k = 2
输出: ["i", "love"]
解析: "i" 和 "love" 为出现次数最多的两个单词,均为2次。
    注意,按字母顺序 "i" 在 "love" 之前。
#692. 前K个高频单词
from collections import Counter
def topKFrequent(words, k: int):
        count = Counter(words)
        candidates = list(count.keys())
        candidates.sort(key=lambda w: (-count[w], w))
        print(candidates)
        return candidates[:k]

words=["i", "love", "leetcode", "i", "love", "coding"]
k = 2
print(topKFrequent(words, k))

from collections import Counter
import heapq
def topKFrequent(words, k: int):
        count = Counter(words)
        # candidates = list(count.keys())
        # candidates.sort(key=lambda w: (-count[w], w))
        # print(candidates)
        # return candidates[:k]
        #堆
        heap,ans=[],[]
        heap = [(-freq, word) for word, freq in count.items()]
        heapq.heapify(heap)
        for i in range(k):
            ans.append(heapq.heappop(heap)[1])
        return ans

words=["i", "leetcode","love", "leetcode", "i", "love", "coding"]
k = 2
print(topKFrequent(words, k))

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值