深入理解数据结构原理(4)—堆(heap)

目录

一、堆的定义

二、堆的用途

三、堆的储存

四、堆的操作

1、插入元素

2、删除堆顶的元素

 2.1、自底向上堆化

2.2、自顶向下堆化

五、堆的排序

1、建立堆

2、排序


一、堆的定义

堆其实就是满足一定条件的树:

在堆中,他的每个结点的值都大于等于(或者小于等于)子树中的所有结点的值。也可以通俗的说任意一个结点的值都大于等于(或者小于等于)所有所有子节点的值。

其中堆不一定是完全二叉树,只是为了方便存储和索引,我们通常用完全二叉树的形式来表示堆而已。

二叉堆:是一个数组,它可以被看成是一个 近似的完全二叉树

堆的分类,根据排序不同可分为:

  • 最大堆 :堆中的每一个节点的值都大于等于子树中所有节点的值
  • 最小堆 :堆中的每一个节点的值都小于等于子树中所有节点的值

可以理解为头大的为大堆,头小的为小堆

图中可以看到最大堆头部根结点21比任何一个子结点都要大,左子结点15也比它的任何一个子结点都要大 ;最小堆恰恰相反,头部最小,比如1这个结点,比任何的子结点都要小。

二、堆的用途

当我们只关心所有数据中的最大值或者最小值,存在多次获取最大值或者最小值,多次插入或删除数据时,就可以使用堆。

相对于有序数组而言,堆的主要优势在于更新数据效率较高。 堆的初始化时间复杂度为 O(nlog(n)),堆可以做到O(1)时间复杂度取出最大值或者最小值,O(log(n))时间复杂度插入或者删除数据,

在java的JVM(Java Virtual Machine)虚拟机里,堆是在“运行时内存”中开辟的一个最大内存空间java中几乎所有的对象实例和数组存储空间都分配于此。  

三、堆的储存

在学习树(tree)的时候知道,储存结构用完全二叉树的来表示的话便利很多,利用数组存储二叉树即节省空间,又方便索引。假如根结点的序号是从 1 开始,那么对于树中任意节点  ,其左子节点序号为  2*i,右子节点序号为  2*i+1。

那么在二叉堆中也可以用完全二叉树的储存结构来进行储存,这样同样具备方便储存和索引

四、堆的操作

1、插入元素

在插入元素的时候,先从底部开始插入,如果插入的元素值比父结点元素值大,则与父结点交换,一直到到比自己数值大的父结点前。(总的来说就是插入元素 :先将元素放至数组末尾,再自底向上堆化,将末尾元素上浮

(1)插入一个元素,值为 (18),最先排在底部

(2)与父结点(7)比较后比父节点值大,与之交换 

 (3)依次与父结点比较,最终在比自己大的父结值点(21)前停下

2、删除堆顶的元素

删除堆定元素,将末尾元素放至堆定,再自定向下堆化,将堆顶元素下沉。也可以自滴下上堆化,只是会产生“气泡”,浪费储存空间。最好的就是采用自定向下堆化的方式

根据堆的性质可知:

  • 最大堆的堆顶元素为所有元素中最大的。
  • 最小堆的堆顶元素是所有元素中最小的。

当我们需要多次查找最大元素或者最小元素的时候,可以利用堆来实现。

在删除堆顶元素后,为了保持堆的性质,需要对堆的结构进行调整,我们将这个过程称之为"堆化",堆化的方法分为两种

  • 一种是自底向上的堆化,上述的插入元素所使用的就是自底向上的堆化,元素从最底部向上移动。
  • 另一种是自顶向下堆化,元素由最顶部向下移动。

 2.1、自底向上堆化

第一步:先删除堆顶元素,让数组下标是  的位置空出来。

第二步比较根结点的左子节点和右子节点,也就是下标为2,3的数组元素(删除结点下的子结点的值比较),将较大的元素填充到根结点(下标为1)的位置。

第三步:如此一来,一直循环比较空出来的位置的左右子结点的值,同样将大值的结点移向空位置直到最低端。   

气泡:每次循环都出现一个空出来的位置。 这样一来会导致存储空间的浪费。

总的来说自底向上的堆化就是从树的顶端开始向下比较空出来位置的左右子结点的值大小,如果谁大谁上,然后继续比较上去。

2.2、自顶向下堆化

引用一个成语就很好理解了《石沉大海》,把石头抬起来再放入海中就会向下沉入。

第一步:把石头拿起来,就是把数组最后一个元素放到树顶 

第二步:然后就是开始沉底过程了,就是比较这个结点下的左右子结点值,让大的子结点和根结点交换

 第四步:依次进行第三步比较,直到元素到达最底端。

五、堆的排序

堆排序的过程分为两步:

  • 第一步是建堆,将一个无序的数组建立为一个堆
  • 第二步是排序,将堆顶元素取出,然后对剩下的元素进行堆化,反复迭代,直到所有元素被取出为止。

1、建立堆

从上面的堆化过程(自底向上堆化、自顶向下堆化)了解到,建堆的过程就是一个对所有非叶节点的自顶向下堆化过程。

……………………

2、排序

……………………

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值