小白学算法1.3——堆
标签: 小白学算法
1.什么是堆
堆是一种特殊的树形数据结构,每个结点都有一个值。通常我们所说的堆是指二叉堆。
当一棵二叉树的每个结点都大于等于它的两个子结点时,它被称为堆有序。
根节点是堆有序的二叉树中最大的结点。
二叉堆(以下简称堆)是一组能够用堆有序的完全二叉树排序的元素,在数组中按照层级存储(一般不使用第一个位置),
- 下图是一个堆有序的完全二叉树:
- 堆一般用数组来存储其元素,因为索引方便快捷。由于一般不使用第一个位置,所以堆中元素起始下标为1,又因为二叉堆是完全二叉树,所以第
k
个结点的父结点为k/2
,子结点为2k
和2k+1
- 二叉堆从任意结点向下都能得到一个非递增的序列
- 二叉堆从任意结点向上都能得到一个非递减的序列
2.堆的实现与算法
当一个堆插入、删除或者改变某个结点的时候,这个堆的有序状态就被打破了,从被打破的状态回到有序状态的过程叫做堆的有序化。堆的所以算法都是为了堆的有序化。
2.1堆的上浮算法
当堆的底部加入结点或者某个结点的值增大的时候,需要用到堆的上浮算法。
void swim(int* a, int k)
{
while(k > 1 && a[k/2] < a[k])//a[k]是子结点并且大于父结点
{
swap(a, k/2, k);
k = k/2;
}
}
2.2堆的下沉算法
当堆的顶部加入结点或者结点的值减小的时候,需要用到堆的下沉算法。
void sink(int* a, int n, int k)
{
while(2*k <= n)//k至少有一个子结点
{
int j = 2*k;
if (j < n && a[j] < a[j+1]) j++;//如果有两个子结点,取较大者
if (a[k] < a[j]) swap(a, k, j);//如果子结点大于父结点
k = j;
}
}
3.总结
- 使用堆可以实现优先队列以及堆排序
- 如果堆的结点从0开始,那么结点
k
的父结点为(k-1)/2
,子结点为2k+1
和2k+2
swim
比较了一次,sink
比较了两次