堆排序
调整堆(AdjustHeap)。调整堆的目的是确保以某个节点为根的子树满足堆的性质(最大堆或最小堆)。这里我们假设要实现的是最大堆。在堆(无论是最大堆还是最小堆)的数据结构中,左子节点和右子节点与它们的父节点之间存在特定的关系。这些关系确保了堆的性质得以维持。对于任何给定的父节点,其左子节点的索引通常可以通过公式 2 * parent_index + 1
计算得出,而右子节点的索引则通过公式 2 * parent_index + 2
计算得出。这里,parent_index
是父节点在数组中的索引。
调整堆
void AdjustHeap(int *nums, int parent, int size){
int temp = nums[parent];
int child = 2 * parent + 1;
while(child < size){
if(child + 1 < size && nums[child] < nums[child + 1]){
child++;
}
if(temp >= nums[child]){
break;
}
nums[parent] = nums[child];
parent = child;
child = 2 * parent + 1;
}
nums[parent] = temp;
}
代码详解如下:
- 函数定义:
void AdjustHeap(int *nums, int parent, int size)
这个函数有三个参数:
nums
:指向整数数组的指针。parent
:当前需要调整的子树的根节点在数组中的索引。size
:数组的大小。
- 取出当前元素:
int temp = nums[parent];
temp存储了当前父节点的值,接下来我们将尝试将这个值放到正确的位置,以确保以该父节点为根的子树是一个最大堆。
- 初始化子节点索引:
int child = 2 * parent + 1;
child` 初始化为父节点的左子节点在数组中的索引。
- 循环调整子节点:
while(child < size)
只要子节点的索引还在数组范围内,就持续调整。
- 找到左右子节点中的较大值:
if( child + 1 < size && nums[child] < nums[ child + 1 ] ){
child++;
}
如果右子节点存在且其值大于左子节点的值,则更新 child
为右子节点的索引。
- 判断父节点是否需要移动:
if (temp >= nums[child]){
break;
}
如果父节点的值已经大于或等于子节点的值,说明父节点已经在正确的位置,跳出循环。
- 移动父节点到子节点的位置:
nums[parent] = nums[child];
将子节点的值赋给父节点,这样父节点就暂时占据了子节点的位置。
- 更新父节点和子节点的索引:
parent = child;
child = 2 * parent + 1;
将父节点更新为刚刚赋值的子节点,并重新计算新的子节点的索引。
- 将 temp 值放到最终的位置:
nums[parent] = temp;
循环结束后,将 temp
(原始父节点的值)放到最终的正确位置。
通过这个过程,我们可以确保以 parent
为根的子树满足最大堆的性质。
交换函数
void swap(int *a, int *b){
int temp = *a;
*a = *b;
*b = temp;
}
排序
void HeapSort(int *nums, int size){
// 1. 构建初始堆
for(int i = size / 2 - 1; i >= 0; i--){
AdjustHeap(nums, i, size);
}
// 2. 堆排序过程
for(int i = size - 1;i > 0; i--){
// 将堆顶元素与当前未排序部分的最后一个元素交换
swap(&nums[0], &nums[i]);
// 重新调整堆(除了已经排序好的最后一个元素)
AdjustHeap(nums, 0, i);
}
}
- 这段代码是堆排序算法中构建初始堆的部分。在堆排序中,我们首先需要把一个无序的数组转换成一个大顶堆(或小顶堆,取决于排序需求)。此时我们转成的是大顶堆。
for (int i = size / 2 - 1; i >= 0; i--) {
adjustHeap(arr, i, size);
}
- 堆排序过程
for(int i = size - 1;i > 0; i--){
// 将堆顶元素与当前未排序部分的最后一个元素交换
swap(&nums[0], &nums[i]);
// 重新调整堆(除了已经排序好的最后一个元素)
AdjustHeap(nums, 0, i);
}
打印函数
void Print(int *nums, int size){
for(int i = 0;i < size; ++i){
printf("%d ",nums[i]);
}
}
完整代码
#include <stdio.h>
void swap(int *a, int *b){
int temp = *a;
*a = *b;
*b = temp;
}
void AdjustHeap(int *nums, int parent, int size){
int temp = nums[parent];
int child = 2 * parent + 1;
while(child < size){
if(child + 1 < size && nums[child] < nums[child + 1]){
child++;
}
if(temp >= nums[child]){
break;
}
nums[parent] = nums[child];
parent = child;
child = 2 * parent + 1;
}
nums[parent] = temp;
}
void HeapSort(int *nums, int size){
for(int i = size / 2 - 1; i >= 0; i--){
AdjustHeap(nums, i, size);
}
for(int i = size - 1;i > 0; i--){
swap(&nums[0], &nums[i]);
AdjustHeap(nums, 0, i);
}
}
void Print(int *nums, int size){
for(int i = 0;i < size; ++i){
printf("%d ",nums[i]);
}
}
int main()
{
int nums[]={5,2,8,9,0,3,7};
int size = sizeof(nums) / sizeof(nums[0]);
HeapSort(nums, size);
Print(nums, size);
return 0;
}