堆排序
代码
C语言代码:
#include <stdio.h>
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
void heapify(int arr[], int n, int i) {
int largest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < n && arr[left] > arr[largest])
largest = left;
if (right < n && arr[right] > arr[largest])
largest = right;
if (largest != i) {
swap(&arr[i], &arr[largest]);
heapify(arr, n, largest);
}
}
void heap_sort(int arr[], int n) {
for (int i = n / 2 - 1; i >= 0; i--)
heapify(arr, n, i);
for (int i = n - 1; i > 0; i--) {
swap(&arr[0], &arr[i]);
heapify(arr, i, 0);
}
}
int main() {
int arr[] = {12, 11, 13, 5, 6, 7};
int n = sizeof(arr) / sizeof(arr[0]);
printf("Given array is \n");
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
heap_sort(arr, n);
printf("\nSorted array is \n");
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
代码解释
- 初始化:数组
arr是待排序的数组,n是数组的长度。 - 交换函数:
swap函数用于交换两个整数的值。
- 堆化函数:
heapify函数用于将子树调整为最大堆。largest初始为根节点i。left是左子节点,right是右子节点。- 比较根、左子节点和右子节点,找到最大值。
- 如果最大值不是根节点,交换并递归堆化受影响的子树。
- 堆排序函数:
heap_sort首先构建最大堆。- 从最后一个非叶子节点开始,向上堆化每个节点。
- 然后逐个将最大元素(根节点)移到数组末尾,并重新堆化剩余元素。
示例运行
假设输入数组为 {12, 11, 13, 5, 6, 7}:
- 初始状态:
{12, 11, 13, 5, 6, 7} - 构建最大堆:
- 堆化从最后一个非叶子节点开始(索引2):
{12, 11, 13, 5, 6, 7}->{12, 11, 13, 5, 6, 7} - 堆化索引1:
{12, 11, 13, 5, 6, 7}->{12, 13, 11, 5, 6, 7} - 堆化索引0:
{12, 13, 11, 5, 6, 7}->{13, 12, 11, 5, 6, 7}
- 堆化从最后一个非叶子节点开始(索引2):
- 开始排序:
- 交换根节点和最后一个元素:
{13, 12, 11, 5, 6, 7}->{7, 12, 11, 5, 6, 13} - 堆化根节点:
{7, 12, 11, 5, 6, 13}->{12, 7, 11, 5, 6, 13} - 交换根节点和倒数第二个元素:
{12, 7, 11, 5, 6, 13}->{6, 7, 11, 5, 12, 13} - 堆化根节点:
{6, 7, 11, 5, 12, 13}->{11, 7, 6, 5, 12, 13} - 继续上述过程直到数组排序完成。
- 交换根节点和最后一个元素:
- 最终结果:
{5, 6, 7, 11, 12, 13}
时间复杂度分析
堆排序的时间复杂度主要取决于构建堆和排序的过程。
- 最优时间复杂度:,因为每次堆化操作需要对数时间。
- 最坏时间复杂度:,无论输入数组的初始顺序如何,执行的步骤基本一致。
- 平均时间复杂度:,对于大多数输入数组,堆排序的性能都很稳定。
空间复杂度分析
堆排序在原地排序,不需要额外的辅助空间,因此空间复杂度为 。
优缺点
优点:
- 时间复杂度稳定,适用于大规模数据排序。
- 不需要额外的辅助空间,空间复杂度低。
- 无论输入数组的初始顺序如何,时间复杂度保持一致。
缺点:
- 不稳定排序算法,可能改变相同元素的相对顺序。
- 实现复杂度相对较高,理解和编程上比简单排序算法复杂。
适用场景
堆排序适用于以下场景:
- 数据量较大的排序。
- 需要一个高效且空间复杂度低的排序算法时。
- 不需要稳定排序的场景。
总结
堆排序是一种高效的排序算法,通过构建最大堆,将最大元素逐个移到数组末尾并重新堆化剩余元素。尽管其实现复杂度较高且不稳定,但在处理大规模数据时表现优异,是一种时间复杂度稳定且空间复杂度低的排序算法。