【0】README
1)本文旨在给出 推排序的源码实现;堆排序是基于二叉树的数组实现的;
【1】堆排序步骤
step1)对排序数据建堆,执行 n 次 insert 操作(基于上滤操作);每次 insert 包括 将 新元素插入到堆末尾,然后执行 上滤操作;step2)执行 n 次 deleteMin 操作(基于下滤操作),每一次 deleteMin 操作都包含 将 堆的根元素 和 堆最后一个元素交换,并对根 执行 下滤操作;step3)经过 deleteMin 操作后, 堆所在的数组中的元素是 逆序的;
Conclusion)由此可见,堆排序的关键操作是 上滤操作 和 下滤操作;
【2】源码实现(for full source code, please visit https://github.com/pacosonTang/dataStructure-algorithmAnalysis/tree/master/chapter7/review/p170_heap_sort )
1)insert插入操作(基于上滤操作)
// 插入操作 based on 上滤操作.
void insert(BinaryHeap heap, ElementType data)
{
if(heap->size == heap->capacity-1)
{
Error("failed insert() for heap is full.");
}
percolateUp(heap, data);
}
// 上滤操作(key operation)
void percolateUp(BinaryHeap heap, ElementType data)
{
int i;
// 必须将size++.
for(i=++heap->size; data < heap->array[i/2]; i/=2)
{
heap->array[i] = heap->array[i/2];
}
heap->array[i] = data;
}
2)deleteMin操作(基于下滤操作)
// delete minimal from heap based on percolateDown().
void deleteMin(BinaryHeap heap)
{
if(heap->size==0)
{
Error("failed deleteMin() for the heap is empty");
return ;
}
swap(&heap->array[1], &heap->array[heap->size--]); // 将二叉堆的根和二叉堆的最后一个元素交换,size--。
percolateDown(heap, 1); // 执行下滤操作.
}
// 下滤操作(key operation)
void percolateDown(BinaryHeap heap, int i)
{
int child;
int temp;
for(temp=heap->array[i]; (child=leftChild(i))<=heap->size; i=child)
{
if(child<heap->size && heap->array[child] > heap->array[child+1])
{
child++;
}
if(temp > heap->array[child]) // 比较是和 temp=heap->array[index] 进行比较.
{
heap->array[i] = heap->array[child];
}
else
{
break;
}
}
heap->array[i] = temp;
}
int leftChild(int index)
{
return 2*index;
}
// swap a and b.
void swap(ElementType* a, ElementType* b)
{
ElementType t;
t = *a;
*a = *b;
*b = t;
}
对以上代码的分析(Analysis):(最难实现的就是 下滤操作)
A1)第21行 的 child<heap->size 是必须需要的,不要认为 它 和 第19行的 (child=leftChild(i))<=heap->size 雷同了,因为有可能 该节点只有左孩子,而没有右孩子;A2)如下图所示,size=4的堆:节点53就只有左孩子而没有右孩子,所以第21行是不需要执行的,这通过 child<heap->size 来控制;