堆排序是一种就地排序方法(请参看《算法导论》一书),在代码中,我用递归的方法写了一下,排序数由随机数产生。父节点从0开始,父节点与左、右孩子的位置关系为:
(父节点)father : i (左孩子)left : i * 2 + 1 (右孩子)right : i * 2 + 2
代码如下:
/*****************************************
Copyright (c) 2015 Jingshuang Hu
@filename:demo.c
@datetime:2015.09.25
@author:HJS
@e-mail:eleftheria@163.com
@blog:http://blog.csdn.net/hujingshuang
******************************************/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/*****************************************/
#define N 15 //元素个数
#define positive 0 //正向遍历
#define opposite 1 //反向遍历
/*****************************************/
void Heap_Sort(int *data, int n); //堆排序
void Heap_Creat(int *data, int n); //创建堆
void Heap_Max_Adjust(int *data, int pos, int n);//调整为最大堆
void Heap_Show(int *data, int n, int way); //显示堆
/*****************************************/
int main()
{
int i = 0;
int data[N] = {0};
srand((unsigned int)NULL);
for (i = 0; i < N; i++)
{
data[i] = rand() % 50 + rand() % 50;
}
//显示随机数
printf("原数据:");
Heap_Show(data, N, positive);
//创建最大堆
Heap_Creat(data, N);
printf("最大堆:");
Heap_Show(data, N, positive);
printf("\n");
//堆排序
Heap_Sort(data, N);
printf("\n堆排序:");
Heap_Show(data, N, opposite);
return 0;
}
/*****************************************/
void Heap_Show(int *data, int n, int way)
{
int i = 0;
if (!way)//遍历方式
{
for (i = 0; i < n - 1; i++)
{
printf("%d ", data[i]);
}
printf("%d\n", data[i]);
}
else
{
for (i = n - 1; i > 0; i--)
{
printf("%d ", data[i]);
}
printf("%d\n", data[i]);
}
}
/*****************************************/
void Heap_Sort(int *data, int n)
{
int temp = 0;
while(n)
{ //顶、底互换(最大值出列,放在末尾)
temp = data[0];
data[0] = data[n - 1];
data[n - 1] = temp;
n--;//保护出列元素
Heap_Max_Adjust(data, 0, n);//自上而下
printf("调整堆:");
Heap_Show(data, N, positive);
}
}
/*****************************************/
void Heap_Creat(int *data, int n)
{
int i = 0;
for (i = (n / 2) - 1; i >= 0; i--)
{
Heap_Max_Adjust(data, i, n);
}
}
/*****************************************/
void Heap_Max_Adjust(int *data, int pos, int n)
{
int temp = 0;
int father = pos; //父节点位置
int left = pos * 2 + 1; //左孩子位置
int right = pos * 2 + 2;//右孩子位置
if (father < (n / 2))
{
if (right < n) //有两个孩子
{ //情况:①父节点与两个孩子相等②左右孩子相等且比父节点大 解决办法:父节点与左孩子(或是右孩子)互换
if ((data[left] >= data[father]) && (data[left] >= data[right]))//此处为父节点与左孩子互换
{
temp = data[left];
data[left] = data[father];
data[father] = temp;
Heap_Max_Adjust(data, left, n);
}
else if ((data[right] > data[father]) && (data[right] > data[left]))
{
temp = data[right];
data[right] = data[father];
data[father] = temp;
Heap_Max_Adjust(data, right, n);
}
}
else //只有左孩子
{
if (data[left] > data[father])//相等不用互换
{
temp = data[left];
data[left] = data[father];
data[father] = temp;
}
}
}
}
在码完代码后,测试发现,随机数中如果没有出现相同的值,则可以正常正确排序;但是如果有两个及其以上的相同值,就会出现排序错误。经调试发现,未考虑到出现相同值得情况,如代码注释中的情况①②。上述代码已修正,是最终可用的版本。