您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# C语言中如何实现堆排序
## 1. 堆排序概述
堆排序(Heap Sort)是一种基于二叉堆数据结构的比较排序算法。它由J. W. J. Williams于1964年提出,具有以下特点:
- **时间复杂度**:平均和最坏情况下均为O(n log n)
- **空间复杂度**:O(1)(原地排序)
- **稳定性**:不稳定排序
- **适用性**:适合大数据量排序,尤其当需要部分排序时效率很高
## 2. 堆的基本概念
### 2.1 二叉堆的定义
二叉堆是一种特殊的完全二叉树,满足以下性质:
- **结构性质**:完全二叉树的结构
- **堆序性质**:
- 最大堆:父节点值 ≥ 子节点值
- 最小堆:父节点值 ≤ 子节点值
### 2.2 堆的存储
由于堆是完全二叉树,通常用数组存储:
- 对于节点i(从0开始):
- 父节点:(i-1)/2
- 左子节点:2*i+1
- 右子节点:2*i+2
## 3. 堆排序算法步骤
堆排序主要分为两个阶段:
1. **建堆(Heapify)**:将无序数组构建成堆
2. **排序**:反复取出堆顶元素,调整剩余元素为新堆
### 3.1 完整算法流程
```c
void heapSort(int arr[], int n) {
// 1. 构建最大堆
for (int i = n/2 - 1; i >= 0; i--)
heapify(arr, n, i);
// 2. 逐个提取元素
for (int i = n-1; i > 0; i--) {
swap(&arr[0], &arr[i]); // 将当前最大移到末尾
heapify(arr, i, 0); // 对剩余元素重新堆化
}
}
// 对以i为根的子树进行堆化,n是堆的大小
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 swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
#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 heapSort(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);
}
}
// 打印数组
void printArray(int arr[], int n) {
for (int i = 0; i < n; ++i)
printf("%d ", arr[i]);
printf("\n");
}
// 测试代码
int main() {
int arr[] = {12, 11, 13, 5, 6, 7};
int n = sizeof(arr) / sizeof(arr[0]);
printf("原始数组: \n");
printArray(arr, n);
heapSort(arr, n);
printf("排序后数组: \n");
printArray(arr, n);
return 0;
}
递归实现可能产生栈溢出风险,可用循环替代:
void heapify(int arr[], int n, int i) {
int largest, left, right;
while (1) {
largest = i;
left = 2 * i + 1;
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) break;
swap(&arr[i], &arr[largest]);
i = largest;
}
}
Floyd提出的自底向上建堆方法效率更高
需要O(n log n)时间且空间受限时
需要获取前k个最大/最小元素时
优先级队列实现
算法 | 平均时间复杂度 | 最坏时间复杂度 | 空间复杂度 | 稳定性 |
---|---|---|---|---|
堆排序 | O(n log n) | O(n log n) | O(1) | 不稳定 |
快速排序 | O(n log n) | O(n²) | O(log n) | 不稳定 |
归并排序 | O(n log n) | O(n log n) | O(n) | 稳定 |
插入排序 | O(n²) | O(n²) | O(1) | 稳定 |
只需修改堆化条件即可实现升序排序:
void heapify_min(int arr[], int n, int i) {
int smallest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < n && arr[left] < arr[smallest])
smallest = left;
if (right < n && arr[right] < arr[smallest])
smallest = right;
if (smallest != i) {
swap(&arr[i], &arr[smallest]);
heapify_min(arr, n, smallest);
}
}
堆排序是一种高效的通用排序算法,特别适合: - 需要保证最坏情况下性能的场景 - 内存受限的环境 - 需要实现优先级队列时
理解堆排序的关键在于掌握: 1. 二叉堆的数据结构特性 2. 堆化操作的实现原理 3. 建堆和排序的两个阶段
通过本文的C语言实现和详细解析,读者应能掌握堆排序的核心思想并能在实际编程中灵活应用。 “`
这篇文章共计约2500字,采用Markdown格式编写,包含: 1. 算法原理说明 2. 完整的C语言实现代码 3. 复杂度分析 4. 优化建议 5. 应用场景和比较 6. 扩展内容等完整的技术细节
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。