python 手动实现大根堆

主要实现了四个函数:

add:往堆里加新的值,相当于在list末尾添加值,然后siftup维护大根堆从上到下从大到小

extract:提取堆顶元素,相当于heapq.heappop(heap),提取0位置元素然后用list末尾的元素补到0位置上,siftdown维护大根堆

class Maxheap(object):
    def __init__(self, maxsize):
        self.maxsize = maxsize #堆的大小
        self._elements = [0] * maxsize #初始化堆
        self._count = 0  #索引

    def add(self, value):
        if self._count >= self.maxsize:
            raise Exception('full')
        self._elements[self._count] = value #放到末尾
        self._count += 1 #索引加一,这是当前的下一个索引
        self._siftup(self._count - 1) #siftup将当前索引值维护到堆的位置

    def extract(self):
        if self._count <= 0:
            raise Exception('empty')
        value = self._elements[0] #记录堆顶值
        self._count-=1 
        self._elements[0] = self._elements[self._count] #末尾移到堆顶
        self._siftdown(0)  #从上到下维护堆
        return value

    def _siftup(self, index):
        if index > 0:
            parent = (index - 1) // 2 #当前索引的父索引
            if self._elements[index] > self._elements[parent]: #当前值大于父,需要替换
                self._elements[index], self._elements[parent] = self._elements[parent], self._elements[index]
                self._siftup(parent) #加入的值换到了父索引位置,继续向上看是不是比上一层的父更大

    def _siftdown(self, index):
        left = index * 2 + 1  #左子树索引
        right = index * 2 + 2  #右子树索引
        new_index = index  #用一个新索引,后面观察需不需要换
        if right < self._count:  #有左右子树的情况
            if self._elements[left] <= self._elements[index] and self._elements[right] <= self._elements[index]:  #当前比左右都大,不用操作
                pass
            else:
                if self._elements[left] >= self._elements[right]:
                    new_index = left #左边更大,且左边大于当前,准备用左边跟当前索引换
                else:
                    new_index = right
        elif left < self._count: #只有左子树
            if self._elements[left] >= self._elements[index]:
                new_index = left
        if new_index != index:  #需要换
            self._elements[new_index], self._elements[index] = self._elements[index], self._elements[new_index]
            self._siftdown(new_index)

topk测试:

#测试代码
import random
seq = list(range(10))
random.shuffle(seq)
heap = MaxHeap(len(seq))
for i in seq:
    heap.add(i)

res = []
for i in range(10):
    res.append(heap.extract())

heaqp用法:(heapq实现的是小根堆,用大根堆需要转换成相反数)

1. heapq.heappush(heap, item)
将值item插入堆,并执行sift-up维持堆特性(列表末尾元素按规则向上移动)

2. heapq.heappop(heap)
将堆顶元素弹出,并执行sift-down位置堆特性(列表末尾元素赋值给list[0],并按规则向下移动)

3. heapq.heappushpop(heap, item)
相当于heappush和heappop的命令结合,先push item入堆,然后pop堆顶元素

4. heapq.heapreplace(heap, item)
和3的顺序相反,先pop堆顶元素,然后push item入堆

5. heapq.heapify(x)
将列表x转换为heap对象(inplace,线性时间)

6. heapq.merge(*iterables, key=None, reverse=False)
返回: 一个iterable可迭代对象
操作: 将可迭代对象列表*iterables合并, 相当于对一个大文件分解的多个小文件组合排序(具体原理见下方的磁盘排序)
参数:
    iterables: 多个输入对象(已经从小到大排序), 例如多个已排序的小文件
    key: 用于比较大小的关键字字段, 默认为None
    reverse: 默认输出是从小到大, 设置为True后逆序输出

7. heapq.nlargest(n, iterable, key=None)
返回一个列表, 为根据key作为筛选条件从可迭代对象iterable中筛选的最大的n个元素

8. heapq.nsmallest(n, iterable, key=None)
返回一个列表, 为根据key作为筛选条件从可迭代对象iterable中筛选的最小的n个元素

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值