【数据结构与算法拓展】二叉堆原理、实现与例题(C和java)

前言

数据结构,一门数据处理的艺术,精巧的结构在一个又一个算法下发挥着他们无与伦比的高效和精密之美,在为信息技术打下坚实地基的同时,也令无数开发者和探索者为之着迷。

也因如此,它作为博主大二上学期最重要的必修课出现了。由于大家对于上学期C++系列博文的支持,我打算将这门课的笔记也写作系列博文,既用于整理、消化,也用于同各位交流、展示数据结构的美。

此系列文章,将会分成两条主线,一条“数据结构基础”,一条“数据结构拓展”。“数据结构基础”主要以记录课上内容为主,“拓展”则是以课上内容为基础的更加高深的数据结构或相关应用知识。

欢迎关注博主,一起交流、学习、进步,往期的文章将会放在文末。


二叉堆原理

这一节,我们我们来介绍一个非常有趣且经典的数据结构——二叉堆

二叉堆的主要作用场合在于维护一个集合,使其能够以最快的速度获取集合中的最值,同时支持弹出最值、插入新的值,并以尽可能小的代价维护它

具体一点说,是希望每次可以以 O ( 1 ) O(1) O(1)的复杂度获取最值。同时删除最值和插入新值后应该在 O ( l o g 2 n ) O(log_2n) O(log2n)的时间内完成对集合的维护。那么根据获取的最值是极大值还是极小值可以将堆分为大根堆小根堆

这个数据结构之所以经典,是因为他在很多经典的算法中都有着应用的身影:哈夫曼编码算法,dijkstra算法,堆排序算法等等不胜枚举。这正是因为它解决的问题是最基础,最普遍的一类问题——求集合最值。

那么如何维护一个集合使其能够快速的获得最值呢。其实这个问题可以借鉴生活中的经验:沙堆

诸位来看这张图片在这里插入图片描述
有没有一些灵感迸发呢?
还没有也没关系,我们来接着看这张二叉树的图片在这里插入图片描述
可以发现,如果将集合中的数据填在每个结点上,并且保证层级间的大小关系,那么根据树的递归定义性质就能够轻松的将全部的数据构造成一颗二叉树并且在二叉树的根部取得最值。据说灵感来自于淘汰赛制。

以小根堆为例,对于集合 { 1 , 6 , 8 , 10 , 2 , 5 , 15 } \{1,6,8,10,2,5,15\} { 1,6,8,10,2,5,15},可以构造成如下的二叉树:
在这里插入图片描述
对于上图树中的每个结点来说,其值都小于其子节点的值。

有的朋友会说,这样一来,二叉树形态岂不是可以乱来?毕竟满足这个条件的二叉树情况太多了。

我说小伙子你不懂,构建堆要将武德,可不能乱来。如果你乱建堆导致算法出错,那希望你耗子尾汁。
在这里插入图片描述

二叉堆存储

二叉堆中结点的位置和顺序有讲究,首先需要它是一棵完全二叉树,其中结点的位置又和存储有很大关系。毕竟:

只讨论逻辑而不考虑存储的数据结构是有灵魂而无肉体的
——沃茨基硕德

如何存储这个二叉树才好呢?我们要先了解一下完全二叉树的概念,下面不妨截取一段来自百度百科的定义
在这里插入图片描述

可以看到,完全二叉树中每个位置的结点都是有确定且紧密排列的编号的,这就能够使我们想到前面学到的数组。实际上,用数组完全可以存储完全二叉树,我们也经常要这么做

所以在存储堆的问题上,就采用顺序存储结构来完成对二叉树的存储

按照上面的定义,给二叉堆的结点按照从上到下,从左到右的顺序编个号,就像下面这样:
在这里插入图片描述
将上面的二叉树存储在数组中就是:
在这里插入图片描述

于是根据这些规则就会产生一些不得了的性质:

  • 根节点的编号为1
  • 结点k的父节点为 ⌊ k 2 ⌋ \lfloor \frac k 2 \rfloor 2k
  • 结点k的左儿子为 k ∗ 2 k * 2 k2
  • 结点k的右儿子为 k ∗ 2 + 1 k*2 + 1 k2+1

有了这些性质,一个堆便被我们表示成为一个数组了。

二叉堆维护及实现

让我们先用数组封装二叉堆的底层,接着再来一步步的完成二叉堆的各项需求,为了演示方便,我们还是以小根堆为例:

//c
#define N ...
int heap[N];//这个数组用来存放二叉树结点。
int size = 0;//堆中当前结点数
//java
public class Heap {
   
	private int[] heap;
	private int size;
	private int maxSize;
	
	public Heap(int maxSize) {
   
		this.maxSize = maxSize;
		heap = new int[maxSize];
	}
}

二叉堆维护

接下来我们要介绍维护二叉堆的两个至关重要的操作:上浮(up)和下沉(down)
他们是二叉堆保持性质的基础

上浮操作意在将一个元素不断地向上和父节点交换,直到该元素比父元素大或成为堆顶

下沉操作意在将一个元素不断地向下和子节点交换,直到该元素比子元素小或无子元素

上浮和下沉操作是堆结构的重中之重,建议读者重点理解。

上浮操作:

对于上浮操作,我们给出如下算

  • 13
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值