堆排序简介
堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆。时间复杂度为O (nlgn)。
堆排序的模拟过程可以看链接:HeapSortion
大根堆:大根堆要求根节点的关键字既大于或等于左子树的关键字值,又大于或等于右子树的关键字值
以下图片取自维基百科:
小根堆:其中任一非终端节点的数据值均不大于其左子节点和右子节点的值
以下图片取自维基百科:
实现过程
堆排序思路:
1. 将数组构建成大根堆
2. 将根节点与最后一个数字交换,重新构建堆
构建大根堆:
首先,我们需要知道堆中父节点与子节点之间的关系:
现在有一个数组a[5], 构建成堆的话将如下图所示:
很明显:
如果节点为 i, 则它的父节点为i/2 + 1
或者i/2 + 2
, 取决于 i 是偶数还是奇数
它的子节点为2*i + 1
或者2*i+2
为了比较容易地理解插入排序,我们可以列出一组数据,比如:
1,7,6,8,0
- 将数组构建成大根堆
至此大根堆构建完成:
- 将根节点与最后一个数字交换
代码实现
#include <stdio.h>
void print(const int *a, const int length) {
int i;
for (i = 0; i<length; i++) {
printf("%d ", a[i]);
}
putchar('\n');
}
void exchange(int *a, const int i, const int j) {
int tmp = *(a + i);
*(a + i) = *(a + j);
*(a + j) = tmp;
}
int getPar(int pos) {
//父节点地址
int par_pos;
if (pos == 0)
return 0;
if (pos % 2 == 0) { //偶数
par_pos = pos / 2 - 1;
}
else { //奇数
par_pos = pos / 2;
}
return par_pos;
}
void _heap(int *a, int low, int high) {
if (low <= high) {
//与子节点比较,重建大根堆
int child_1 = low * 2 + 1;
int child_2 = low * 2 + 2;
if (child_2 <= high) {
if (a[child_1] > a[child_2]) {
if (a[child_1] > a[low]) {
exchange(a, child_1, low);
_heap(a, child_1, high);
}
}
else {
if (a[child_2] > a[low]) {
exchange(a, child_2, low);
_heap(a, child_2, high);
}
}
}
else if (child_1 <= high && child_2 > high) {
if (a[child_1] > a[low]) {
exchange(a, child_1, low);
_heap(a, child_1, high);
}
}
}
}
void heapSort(int *a, const int low, const int high) {
//1.构建大根堆,排序
for (int i = high; i > 0; i--) {
int parent = getPar(i);
int bro;
if (i % 2 == 0) {//偶数
bro = i - 1;
if (a[bro] > a[i]) {
if (a[parent] < a[bro]) {
exchange(a, bro, parent);
_heap(a, bro, high);
}
}
else {
if (a[parent] < a[i]) {
exchange(a, i, parent);
_heap(a, i, high);
}
}
i--;
}
else { //奇数
if (a[parent] < a[i]) {
exchange(a, parent, i);
_heap(a, parent, high);
}
}
}
print(a, high - low + 1);
//2.与最后一个数交换
for (int i = high; i > 0; i--) {
exchange(a, i, 0);
//重排
//print(a, high - low + 1);
_heap(a, 0, i-1); //不是i,而是i-1
}
}
void main() {
const int length = 4;
int my_array[5] = { 1 ,7, 6, 8, 0 };
heapSort(my_array, 0, length-1);
print(my_array, length);
}
代码精简
void HeapSortBase(int *a, const int length){
for(int i=0; i<length; i++){
int dad = i;
int dad_father;
//两个子节点与父节点分别进行比较
for(int plus=1; plus<3; plus++){
int son = 2*dad+plus;
// 父节点大于子节点
if(a[dad]>a[son] && son<length){
swap(&a[dad], &a[son]);
//判断父节点是否小于它的父节点
do{
dad_father = (dad-1)/2;
swap(&a[dad_father], &a[dad]);
}while(a[dad_father]>a[dad] && dad_father>=0);
}
}
}
}
void HeapSort(int *a, const int length){
for(int i=0; i<length; i++){
//父节点是最小的
HeapSortBase(a+i, length-i);
}
}