堆排序是选择排序的一种,下面是堆排序的一些特征:
- 时间复杂度,最好最坏平均都为:O(nlog2n)
- 空间复杂度,最好最坏平均都为:O(1)
- 是否稳定:不稳定
- 建堆的时间复杂度为:O(n)
堆排序的一次循环可以将最大或者最小的一个元素放在最终位置上
tip: 你需要了解的前置知识有 二叉树相关概念,完全二叉树的连续存储方式,完全二叉树的一些数学特性
下面是堆排序的代码,建立的堆是大顶堆,每次会把最大的一个元素放在最终位置上:
/**
* arr 数组首地址
* len 数组长度
*/
void heap_sort(int *arr, int len)
{
int i;
build_max_heap(arr, len); // 建立大顶堆
for (i=len-1; i>0; i--) { // 排序
swap(arr, arr+i); // 将最大的元素放到最后面
adjust_down(arr, 0, i); // 使前len-1个元素重新变成大顶堆
}
}
/**
* 交换两个元素的值
*/
void swap(int *px, int *py)
{
int temp = *px;
*px = *py;
*py = temp;
}
/**
* 建立大顶堆
*/
void build_max_heap(int *arr, int len)
{
int i;
for (i=len/2-1; i>=0; i--)
adjust_down(arr, i, len);
}
/**
* 将元素k向下进行调整
*/
void adjust_down(int *arr, int k, int len)
{
int i;
int temp = arr[k];
for (i=2*k+1; i<len; i=i*2+1) {
if (i<len-1 && arr[i]<arr[i+1])
i++; // 选取较大的子结点
if (temp>=arr[i]) break;
else {
arr[k] = arr[i]; // 将arr[i]上调
k = i;
}
}//for
arr[k] = temp;
}
测试代码,可直接复制后编译执行:
#include <stdio.h>
void show(int arr[], int len);
void swap(int *px, int *py);
void heap_sort(int *arr, int len);
void build_max_heap(int *arr, int len);
void adjust_down(int *arr, int k, int len);
int main()
{
int len = 7;
int arr[] = {7, 10, 11, 9, -8, 2, 27};
heap_sort(arr, len);
show(arr, len);
return 0;
}
void show(int arr[], int len)
{
int i;
for (i=0; i<len; i++) {
printf("%4d", arr[i]);
}
printf("
");
}
/**
* 交换两个元素的值
*/
void swap(int *px, int *py)
{
int temp = *px;
*px = *py;
*py = temp;
}
/**
* arr 数组首地址
* len 数组长度
*/
void heap_sort(int *arr, int len)
{
int i;
build_max_heap(arr, len); // 建立大顶堆
for (i=len-1; i>0; i--) { // 排序
swap(arr, arr+i); // 将最大的元素放到最后面
adjust_down(arr, 0, i); // 使前len-1个元素重新变成大顶堆
}
}
/**
* 建立大顶堆
*/
void build_max_heap(int *arr, int len)
{
int i;
for (i=len/2-1; i>=0; i--)
adjust_down(arr, i, len);
}
/**
* 将元素k向下进行调整
*/
void adjust_down(int *arr, int k, int len)
{
int i;
int temp = arr[k];
for (i=2*k+1; i<len; i=i*2+1) {
if (i<len-1 && arr[i]<arr[i+1])
i++; // 选取较大的子结点
if (temp>=arr[i]) break;
else {
arr[k] = arr[i]; // 将arr[i]上调
k = i;
}
}//for
arr[k] = temp;
}