大家好,这里是国中之林!
❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看←
一.堆的原理
在现实生活中,我们经常会有比赛,比赛呢,往往会有冠军,亚军等等
我们几乎所有人都只会记住冠军,但是很少有人会记住亚军,就像劳大说过的一句话:“第二是最大的失败者!”
但是有的情况,第二还真的就不一定是第二,当裁判们发现了第一名作弊,那么我们就会将亚军升成冠军.
那么这样就需要我们对排序进行保存,这样才能很好的,供我们操作,所以我们就选用了堆来做为排序的存取.
二.堆的特点
可能说到堆,大家不知道是什么.
堆是一个完全二叉树结构.
像这样:
那我们观察一下这个有什么特点呢?
每个节点最多有两个子节点
是一个完全二叉树结构,这意味着除了最底层的叶子节点和根节点,其他层数都是完全填满的,只运行根节点没有兄弟节点,和最后一个左子节点可以没有兄弟节点,其他节点必须有兄弟节点.
意思就是这样也是一个堆.
现在我们来看看数字,父节点一定大于子节点,根节点是最大的,这是最大堆的表现
堆只分为最大堆和最小堆.
三.在数组中创建堆
那么为什么我们的堆姚有这些特点呢?
答案是为方便我们在数组中进行创建堆.
假设图上标的是在数组中的下标,那我们可以利用规律
知道父节点找子节点:左子节点i*2+1 右子节点i*2+2
知道子节点找父节点:(i-1)/2
那么我们就可以很好的进行选择操作.
那么我们如何在乱序的数组中,创建最大堆或者最小堆呢?
很明显,现在不满足最大堆的特点,是按数组顺序排放的.
那么我们如何将其转换成为最大堆呢?
因为我们知道数组的长度,我们可以很容易的知道最后一个节点的下标.
然后根据我们刚刚的公式,就可以自动父节点的下标
然后其父节点的指和自己的子节点分别做比较,最大的值,赋值到父节点,小的,放在子节点.
然后对父节点减一,判断其他的父节点,直到下标减到0,也就是根节点,值得注意的一点是,如果换到子节点后,还有子节点,那么还需要继续判断.
这就是创建最大堆的过程.
四.堆的数据结构
跟顺序表一样,就是一个数组.
五.初始化堆
传入数组和数组的大小拷贝到我们的堆中.
六.建堆
1.遍历父节点
我们已经知道要将最后一个节点的父节点一直遍历到根节点来分别判断最大值.所以我们需要遍历父节点进行判断最大值操作.
这里传入的不是下标值,是数组的个数,所以我们不用刚刚的公式,用size/2-1得到父节点的下标.
然后一直减减遍历到根节点.
2.向下调整交换
我们传入的index是父节点的下标.
我们先将父节点的值进行保存.
从父节点开始,循环的条件是,看其子节点下标有没有有没有超过元素的个数.没有则说明还存在子节点,就开始比较.
如果存在两个子节点,先比较选出大的子节点,然后与父节点进行必须,如果父节点大,那么不变,如果最大的子节点大,那么交互值.
交换值以后的子节点赋值成为父节点,再判断有没有子节点,有的话,刚刚的流程再来一遍.
七.总结
我们要知道堆的特性,这样我们才能用数组来创建堆.
其次就是公式,父节点找子节点,子节点找父节点.
还有如何比较来创建堆.