堆排序
在数据结构之堆的基本操作这篇博客当中提到过一个堆排序。就是将一个堆的元素删除完毕过后,此时的数组内部就是一个有序的序列。
堆与排序
堆是一个完全二叉树,堆的任意一个节点都是以这个节点为根节点的树中的最值(最大或最小值)这样子的话,每一个堆的堆顶元素都是这个堆的最值。那么依次删除一个堆的堆顶,最后就能够得到一个有序的序列。
而堆排序就是利用了堆的这个性质来进行排序的过程。
思路
在进行彻底的删除完毕后,剩下的序列就是 2 3 4 5 6 9 这就就是一个有序的序列!!
所以堆排序的主要思路就是两个:
- 将数组构建成一个堆
- 依次删除这个堆
实现
void AdjustDown(int array[], int parent, int size) // 下沉式调整
{
int child = 2 * parent + 1;
while (child < size) {
if ((child + 1) < size && array[child] < array[child + 1]) {
child = child + 1;
}
if (array[parent] < array[child]) {
Swap(&array[parent], &array[child]);
parent = child;
child = 2 * parent + 1;
} else {
break;
}
} // end while (1)
return;
}
void HeapCreate(int array[], int size)
{
if (size <= 1) {
return;
}
int parent = (size - 1 - 1) / 2;
for (; parent >= 0; parent--) {
AdjustDown(array, parent, size);
}
return;
}
void HeapPop(int array[], int heap_bound)
{
Swap(&array[0], &array[heap_bound - 1]);
AdjustDown(array, 0, heap_bound - 1);
}
void HeapSort(int array[], int size)
{
if (size <= 1) {
return;
}
HeapCreate(array, size); // 创建堆
int i = 0;
for (; i < size; ++i) {
// 由于每次删除堆的元素后
// 堆的范围就变了
// 所以这里定义一个 heap_bound
// 来确定堆的范围
int heap_bound = size - i;
HeapPop(array, heap_bound);
}
return;
}
堆的操作最核心的就是下沉与上浮,由于堆的删除是进行下沉操作的,所以这里在构建堆的时候也使用下沉的方式来构建堆。构建堆的时候先找到第一个父节点,可以根据最后一个叶子节点来计算出其父节点,接下来就是依次遍历,依次下沉的过程,最终构建一个堆。
删除的时候就是一个简单的堆顶删除,与最后一个叶子节点交换,接着下沉堆顶的叶子节点即可。
切记!!!
这里要注意的是,由于每次删除后,堆内元素减少,同时在下沉传参的时候一定要注意好传什么参数进去,以免对不属于堆的元素进行操作。
堆排序的时间复杂度是 O(N*logN),空间复杂度是 O(1)由于这里我们在原有的数组内部建立堆,并没有创建新的空间,所以是O(1),排序稳定性:不稳定。
欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!