堆解密,二叉堆到底是树还是队列,二叉堆和堆栈有关系吗?

在学习计算机编程的时候,堆栈是我们最经常使用到的概念,也是2种最基本的内存管理方式。可是在数据结构算法也有一个,还有叫二叉堆的,那么堆栈的堆、堆、和二叉堆,到底是什么,它们之间有关系吗,本文就是来解密。

先说结论,数据结构中的二叉堆是一个概念,它们和内存管理中的没有半毛钱的关系。为了区别说法,本文我们称前者是二叉堆,后者叫内存堆

内存堆

内存堆通常和栈出现在一起叫内存堆栈:

  • 栈:是指函数调用是参数和局部变量的存储方式。在函数调用的时候由系统分配一块连续内存,局部变量都存在在栈中,在函数结束后统一释放。函数间的调用关系也是由函数栈通过先进先出的规则管理。
  • 堆:是动态分配的,需要程序主动控制。

二叉堆

设想我们有一个垃圾桶问题。假设:

  • 总共有7个固定的放垃圾桶的位置
  • 垃圾车隔10分钟来一次,每次把一个最重的垃圾桶拉走
  • 居民每隔10分钟会放一个新的垃圾桶,重量不定

要求设计一个方案,使得工作最轻松。


方案一,没有任何设计的情况

  • 垃圾车取垃圾时,要每个秤一遍,选取最重的后拖走
  • 居民看到空的位置放上去。
    这个方案,垃圾车每次都需要:秤7次

方案二,每次都排序好

既然,垃圾车每次都要秤7次,不如我们先排好序,方案如下:

  • 垃圾车每次都在1号位置取
  • 居民没次把垃圾桶排好序。
    这个方案优化了垃圾车都是一次搬走,但是对于居民每次要排序,怎么排呢?最节省的方式是用二分查找,如下图:

    先秤4号位置的垃圾桶,如果更轻,则再比较6号位置的,如果更轻,则最后比较7号位置的,如果还是更轻,则所有的桶需要向前移动一位,然后放到7号位置,如下图:

    该方案的最坏情况,每次需要:秤3次,移6次

二叉堆出场

二叉堆排序,满足以下要求:

  • 全二叉树(即:一定要先填满上面的)
  • 父节点比子节点重:如上所示,1比2和3重,2比4和5重,3比6和7重。

注意:这不是二叉搜索树,二叉搜索树是父节点比左子节点重,但比右子节点轻。

  • 二叉堆看着是二叉树,实际上在存储中还是使用数组,由于是全二叉树,子节点可以通过2*k2*k + 1来定位。比如对于3号位置,其子节点就是3*2=63*2+1=7号位置。
    先看垃圾车的操作,最重在1号位置,所以1次搬走。
    再看居民的操作,假设新来一个垃圾桶是6kg:
    第一步:首先填上空着的1号位置,如下图。之后,要把1号位置下沉到合适位置。

  • 第二步:先和两个子节点比较,即2和3号位置,如果都比它们重则完成,否则和最重的交换位置,本例中,和3号交换位置如下。这一步:秤2次,移动1次


  • 第三步:先和两个子节点比较,即6和7号位置,如果都比它们重则完成,否则和最重的交换位置,本例中,和7号位置交换。这一步:秤2次,移动1次。



    最坏的情况:秤4次,移2次

比较3种算法

方案 操作次数 复杂度
方案一 秤7次 O(N)
方案二 秤3次,移6次 O(N)
方案三 秤4次,移2次 O(Log(N))

显然方案三最优。因为数量较少,所以方案三的优势不明显,当数量逐渐增加时,Log(N)和N的差距就会越来越大。当有10000个垃圾桶时,以下是数据,这个优势就是数量级的:

方案 操作次数 复杂度
方案一 秤10000次 O(N)
方案二 秤13次,移9999次 O(N)
方案三 秤14次,移14次 O(Log(N))

总结

  • 内存堆栈的堆和数据结构中的堆,没有联系,它们只是都有上面小下面大,有点像米堆,呵呵;
  • 二叉堆二叉搜索树的区别是,前者父节点比子节点都大,后者是父节点比左节点大,比右节点小;
  • 二叉堆算法被普遍用于调度算法中,其核心操作是获取最大的插入二叉堆保证所有操作的复杂度在log(N)。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章