1.堆排序定义
堆排序是一种树形选择排序方法,特点是在排序的时候,可以将拥有n个关键字的数组或其他结构看做一个完全二叉树。
如图:
堆的定义:n个关键字序列L(1...n)称为堆,当满足:
L(i) <= L(2i) 且 L(i) <= L(2i+1) ( 1 <= i <= [n/2] ) 也就是说小于左右孩子 ,称之为小顶堆;如右图。
L(i) >= L(2i) 且 L(i) >= L(2i+1) ( 1 <= i <= [n/2] ) 也就是说大于左右孩子 ,称之为大顶堆;如左图。
2.堆的性质
在进行堆排序之前,我们需要知道,堆是一种基于完全二叉树的结构,所以具有完全二叉树的性质,如根节点为 i 的节点:
- 左孩子为2i
- 右孩子为2i+1
- 父节点为[ i/2 ]
3.堆排序算法
先随机建立一个堆,将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根节点。将它与第一个元素进行交换(此时末尾元素就是最大值),然后将剩余的n -1 个序列重新构造成一个大顶堆,这样就会得到 n 个元素中的次小值。如此反复就得到了一个有序序列了。
先看heapsort.h文件
此处放需要的头文件及函数声明
#ifndef _HEAPSORT_H
#define _HEAPSORT_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
void headSort(int arr[], int length); //创建大顶堆
void swap(int arr[], int i, int j); //交换数据值
void heapadjust(int arr[], int key, int length); //实现堆排序
#endif
heapsort.c
函数实现
#include "heapsort.h"
void swap(int arr[], int i, int j)
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
void heapadjust(int arr[], int key, int length)
{
arr[0] = arr[key];
int i;
for ( i = 2 * key; i <=length; i=i*2) //从左孩子开始
{
if (i < length && arr[i] < arr[i + 1]) //取左右孩子的最大值
++i;
if (arr[0] >= arr[i]) //判断该节点的值是否其子节点的值
break;
arr[key] = arr[i]; //将子节点最大的赋值给根节点
key = i;
}
arr[key] = arr[0]; //将值放在最终位置
}
void headSort(int arr[], int length)
{
int i;
for(i = length / 2; i > 0; i--)
heapadjust(arr, i, length);
for (int i = length; i > 1; i--) //n-1建堆并获得n-个次小值
{
swap(arr, 1, i); //将堆顶与堆底元素交换
heapadjust(arr, 1, i-1); //剩余元素继续建堆
}
}
最后来看main.c
#include "heapsort.h"
int main()
{
srand(time(NULL));
int length = 20;
int arr[length];
arr[0] = 0;
for(int i = 1; i < length; i++) //随机建立一个堆
arr[i] = rand()%100;
printf("排序前:\n");
for (int i = 1; i < length; i++)
printf("%d ", arr[i]);
headSort(arr, length - 1);
printf("\n排序后:\n");
for (int i = 1; i < length; i++)
printf("%d ", arr[i]);
printf("\n");
}
这是在linux下运行的,将文件放于同一目录下,编译运行即可。