在堆和优先队列讲过用上滤法建堆的过程,然后堆排序的时候又要用到下滤法。其实下滤也可以实现建堆的过程:以最大堆为例,考虑深度最大的一层父结点,如果存在父结点比子结点小,那么父结点下沉,子结点上移,这个过程实现了较大的结点上滤,较小的结点下滤,至此完成了树的最底两层的有序排列。然后考虑倒数第三层和倒数第二层的排序,同样是一个倒数第二层下滤的过程,注意这个过程可能不止下滤一层,只要比子结点小,那么结点就一直下移,直到根结点也完成了下滤操作。最小堆的情况类似。
#define LeftChild(i) 2*i+1
//最大堆下滤过程
void PercDown(int* a, int n, int i)
{
int tmp, child;
for(tmp = a[i]; LeftChild(i) < n; i = child)
{
child = LeftChild(i);
if(child != n-1 && a[child] < a[child+1]) //最小堆的时候改为“>"
++child;
if(tmp < a[child]) //最小堆的时候改为“>"
a[i] = a[child];
else
break;
}
a[i] = tmp;
}
//建堆过程
for(int i = n/2 - 1; i >= 0; --i)
PercDown(a,n,i);