• 2018暑假集训专题小结 Part.4


    各种堆 √

    这个堆就是普普通通的堆,太简单了,以至于我不想讲。
    就只介绍介绍支持的操作——
    加入一个新点。
    查询最值。
    删除堆顶的点。
    好像就没啦。

    可合并堆(左偏树)

    这个左偏树特别厉害,是堆的一个神奇版。(废话)
    首先,他支持堆的所有操作,并且支持合并两个堆,还有,左偏树是二叉树(堆)。
    实际上,这个左偏树就是在支持合并的基础上进行堆的操作。

    那么我们就来看看左偏树怎么合并的。
    首先我们来看看左偏树记录最主要的一个东东——
    len[]
    这个len的定义是:该节点到 有空的子结点的结点 的距离
    有点绕,不妨看看图:
    这里写图片描述
    我们可以发现一个神奇的性质——
    len[i]=min(len[left_son[i]] , len[right_son[i]])+1
    当且仅当左右都有儿子,否则就:
    len[i]=0

    然后有这个len,我们就可以说明左偏树的性质了——
    左偏树就是对于任意一个点,有两个儿子。
    他们满足左边儿子的len永远大于右边儿子的len值。
    这就是左偏树的性质。

    我们有这个东西,我们就可以考虑合并了。
    这里写图片描述
    这两个堆要合并(数字表示权值)
    由于合并就是一个堆插入到另一个堆中,
    那么我们首先就把堆顶小的看作“被插入堆”(左边),大的看做“插入堆”(右边)。

    然后,我们就对左边的进行插入。
    这里写图片描述
    我们首先看左边的堆的右子树,然后,我们发现,右边的堆可以交换到左边的堆的右子树,那么我们就强行把左边的堆的右子树给提出来,与右边的堆直接交换——
    这里写图片描述
    那么就交换过来啦~ (画图神技)
    然后我们把左边的堆的右子树看做是新的左边堆。
    然后,我们递推重复上面的操作——
    这里写图片描述
    交换:
    这里写图片描述
    最后变成这个样子——
    这里写图片描述
    要注意的一个地方是
    如果右边的堆的顶大于左边堆的右儿子,那么就不交换,继续递归。

    当然,这样做不免会破坏原来的len值,于是我们就在回溯的时候更新即可,然后再通过交换左右儿子的方法来维护左偏树的性质即可。

    这样就是一次交换,时间复杂度大约是log的。
    那么我们来看看如何维护普通堆支持的操作。

    加入一个新点:把原来的左偏树插入一个新的节点即可。
    查询最值:直接查询。
    删除堆顶的点:合并当前左偏树的根的左右子树即可。

    是不是有点强大?
    一个问题:
    会不会一直加入一个点导致右边有一条特别长的链?
    A:不会。因为我们是时时刻刻维护len值的,所以当右边很长的时候,就会交换到左边去,于是就很平衡了。
    一个问题:
    比平衡树平衡吗?
    A:不知道。(这个问题可能没有意义)

    空间复杂度(n)
    时间复杂度(所有操作都是log n)

    斜堆

    这个则是左偏树(可合并堆)的一个简化版。
    它的具体方法就跟左偏树差不多。

    流程:
    1、判断左边堆的右子树与右边堆的大小关系。
    2、交换。
    3、回溯,不看len标号,直接左右子树交换。

    所以说,左偏树与斜堆的主要区别就是没有len标号。
    斜堆不用len标号,然后就是对于每个点都把左右子树交换。
    以此来维持“左偏”
    然而,没有你想象中的那么偏。

    其实它没有严格的像左偏树那样维持“左偏”。
    所以,是有办法把这种做法的右子树变成很长很长的。
    虽然很长,但也就是会把你的栈给卡爆。

    事实上,我不会如何把它卡爆

    有一种非递归的版本——(很好理解,但很难证)
    首先,把每颗树的右子树给切出来。(分离出来)
    然后,就会变成这棵树有根,有左子树或没有,还有一个新的树(切出来的右子树)。
    继续在这个新的树继续切右子树。
    百度上有图,我来转转(以下的图都是转百度的)
    原图——
    这里写图片描述
    然后切一切,之后,我们就按照每颗树的顶点拍序——
    这里写图片描述
    把最右边的树连接到它左边的树的右子树,然后把这棵树左右子树交换——
    这里写图片描述
    依次这样做:
    这里写图片描述
    这里写图片描述
    最后变成——
    这里写图片描述
    这就是非递归版的斜堆。
    其实,证明正确性也是很好感性理解的。

    当然,它可以做很多左偏树的东西(几乎都可以)。
    时间复杂度也是一样的。
    当然,常数小,比较推荐!

    ——————————————————————————
    下次再更:二项堆、斐波那契堆、配对堆
    ——————————————————————————

    我活在这夜里。无论周围多么黑暗,我都要努力发光!我相信着,终有一天,我会在这深邃的夜里,造就一道最美的彩虹。
  • 相关阅读:
    ubuntu下android开发工作环境搭建
    ADB命令行控制界面开关
    chromium os系统编译与环境搭建
    完整代理的简单实现
    OC协议、代理的简单使用
    OC字典的使用
    OC数组的简单使用、NSArray
    OC中NSString的使用、字符串的使用
    OC内存管理、非ARC机制、MRR机制
    OC中重写set和get方法、懒加载
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11148402.html
Copyright © 2020-2023  润新知