手写heap
堆
堆可以理解成一种很想树的数据结构
它可以分为两类
- 小顶堆
- 大顶堆
简单介绍一下小顶堆堆特点
每一个父节点满足值小于两个左右子结点
这样保证了根结点保存的就是最小的值
堆的左右子结点
假如父节点是1,那么左结点为2,右结点为3
同理父亲为2,左右分别为4和5
所以我们可以得出结论 父节点为n ,父节点的左结点为2 * n
,右结点为2 * n + 1
针对堆这种数据结构,主要用来处理以下问题
如何添加元素
heap[++size] = res
如何删除元素
堆和链表不同,如果我们想要删除头结点,是很不方便的,但是如果想要删除尾部结点很容易,于是我们可以通过heap[1] = heap[size] size--; down[i]
的方式来解决该问题
如何获取最小值
heap[1]
Down函数
down函数遵循上面的小顶堆的规则
将插入的元素(比较大的),通过down函数放入到这个堆中的指定位置
示例代码
void down(int u) { |
Up函数
将插入的元素(比较小的),通过up函数向上面进行传递到堆的指定位置
示例代码
void up(int u) { |
如何通过给出的一组数去构建小顶堆呢?
相当于是我们对所有插入的数进行一个down操作或者是up操作
代码模版
const int N = 1000010; |
为什么我们i会从n / 2
开始进行呢?
因为假如我们想象一个三层的满二叉树,我们总共有4 + 3个结点,因为叶子结点是没有左右子结点的所以不需要down,我们只需要处理上面三个结点,将这三个结点放入到合适的位置即可
堆排序进阶
除了上面堆情况之外,题目中还会出现对第n个数字进行操作的可能,这个时候就需要我们去维护两个全新的数组hp
和ph
hp(heap -> point) 用来获取堆中的第n个元素是第几个插入的元素
ph(point -> heap) 用来获得第几个插入的元素在堆中是第几个元素
添加元素
sz++; //用来记录堆中元素的位置 |
交换两个堆中的元素
void heap_swap(int a,int b) { |
删除第n个元素
k = ph[n]; |
修改第n个元素
k = ph[n]; |
注意:最后两种操作,操作后是不满足小顶堆的条件的,我们同时调用down和up本质上只会执行其中的一个