数据结构(四)最大堆、最小堆、堆排序

一、完全二叉树

  • 若二叉树的深度为h,则除第h层外,其他层的结点全部达到最大值,且第h层的所有结点都集中在左子树。

二、定义

  • 堆是一颗完全二叉树;
  • 堆中的某个结点的值总是大于等于(最大堆)或小于等于(最小堆)其孩子结点的值。
  • 堆中每个结点的子树都是堆树。

三、初始化

因为堆是二叉树,因此可以用顺序表存储。

class PrioQueue:
    def __index__(self, elist=[]):
        self._elist = list(elist)
        if elist:
            self.buildheap()
    def is_empty(self):
        return len(self.is_empty()==0)
    def peek(self):
        if self.is_empty():
            raise PrioQueueError("in peek")
        return self._elist[0]

四、插入

插入元素和向上筛选

  • 把新加入的元素放在(连续表)已有元素之后,执行一次向上筛选操作。
  • O(logn)
    def enqueue(self, e):
        self._elist.append(None)
        self.siftup(e, len(self._elist)-1)
    def siftup(self, e, last):
        elems, i, j = self._elist, last, (last-1)//2
        while i > 0 and e < elems[j]:
            elems[i] = elems[j]
            i, j = j, (j-1)//2
        elems[i] = e

五、删除

弹出元素和向下筛选

  • 弹出当时的堆顶。
  • 从堆最后取一个元素作为完全二叉树的根。
  • 执行一次向下筛选。
    def dequeue(self):
        if self.is_empty():
            raise PrioQueueError("in dequeue")
        elems = self._elist
        e0 = elems[0]
        e = elems.pop()
        if len(elems) > 0:
            self.siftdown(e, 0, len(elems))
        return e0
    def siftdown(self, e, begin, end):
        elems, i ,j = self._elist, begin, begin * 2 + 1
        while j < end:
            if j + 1 < end and elems[j+1] < elems[j]:
                j += 1
            if e < elems[j]:
                break
            elems[i] = elems[j]
            i, j = j, 2 * j + 1
        elems[i] = e

六、构建堆

  • O(n)
    def buildheap(self):
        end = len(self._elist)
        for i in range(end//2, -1, -1):
            self.siftdown(self._elist[i], i, end)

七、堆排序

  • 首先构建小顶堆
  • 每次弹出的就是最小值,希望能不利用其他空间,每次弹出就后面就会空出来一个位置,正好存放弹出的元素,不过这样的到的结果是从大到小,可以反转,或者直接构建大顶堆。
def heap_sort(elems):
    def siftdown(elems, e, begin, end):
        i ,j = begin, begin * 2 + 1
        while j < end:
            if j + 1 < end and elems[j+1] < elems[j]:
                j += 1
            if e < elems[j]:
                break
            elems[i] = elems[j]
            i, j = j, 2 * j + 1
        elems[i] = e
    end = len(elems)
    # buid heap O(n)
    for i in range(end//2, -1, -1):
        siftdown(elems, elems[i], i, end)
    # O(nlogn)
    for i in range((end - 1), 0, -1):
        e = elems[i]
        elems[i] = elems[0]
        siftdown(elems, e, 0, i)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值