什么是最小堆?什么又是最大堆?
所有的父结点都比子结点的数值小,符合这样特点的完全二叉树称为最小堆。所有的父结点都比子结点要大,这样的完全二叉树称为最大堆。
如何创建堆?又怎样进行堆排序?
从叶结点开始。(叶节点没有儿子),所以所有以叶结点为根结点的子树都符合最小堆的特性。因此所有的叶结点都不需要处理,直接跳过。从第n/2个结点开始处理这棵完全二叉树。(完全二叉树最后一个非叶结点是第n/2个结点)。
递减排序时,应建大根堆,递增时,选择小根堆
向下调整函数
法一
void shiftdown(int i)
{
if(i==1)
return ;
while(i!=1)
{
if(h[i] < h[i/2])
{
int t=h[i];
h[i]=h[i/2];
h[i/2]=t;
i/=2;
}
else break;
}
}
法二
void Siftdown(int i) //传入一个需要向下调整的结点编号i,开始向下调整
{
int t,flag = 0; //是否需要继续向下调整
//当i结点有儿子(至少有一个左儿子)并且有需要继续向下调整的时候循环就执行
while(i*2 <= n && !flag)
{
if(h[i] > h[i*2]) //判断它和左儿子的关系,并用t记录值较大的结点
t = i*2;
else
t = i;
if(i*2+1 <= n) //如果它有右儿子,再对右儿子进行讨论
{
if(h[t] > h[i*2+1]) //如果右儿子的值更小,更新较大的结点编号
t = i*2+1;
}
if(t != i) //如果发现最小的结点编号不是自己,说明子结点中有比父节点更小的
{
swap(t,i);
i = t; //更新i为刚才与它交换的儿子结点的编号,便于接下来继续向下调整
}
else
flag = 1; //说明父结点比其子结点都要小
}
}
建立堆函数
法一
for(int i=1; i<=4000; i++)
h[i]=inf;
for(int i = 1; i <= n; i++)
{
scanf("%d",&h[i]);
shiftdown(i);
}
法二
void creat() //建立堆函数
{
int i;
for(i = n/2; i >= 1; i--) //在完全二叉树中,从最后一个非叶结点开始
Siftdown(i);
}