您的位置:首页 > 其它

堆排序

2015-08-02 15:44 218 查看
#include "util.h"

//堆排序
//
//二叉堆的特性就是每个节点的数值都比子节点的数据大,所以二叉堆最顶端的数值是最大的
//这里采用数组来存储二叉堆,为了方便计算父节点与叶子节点的索引,数据索引0没有使用,数
//组有效索引从1开始, 给定任意节点索引X,该节点的父节点索引为X/2,该节点的左叶子节点索
//引为 X*2, 右叶子节点索引为X*2+1
//
//       1
//   ---------
//   |       |
//   2       3
// -----   -----
// |   |   |   |
// 4   5   6   7
//
// array |0|1|2|3|4|5|6|7|
//
//堆排序的核心思想就是基于二叉堆的数据结构进行排序算法实现
//1 首先将数据构造成二叉堆
//2 之后将二叉堆顶端最大值与数组末尾的值进行交换,缩小数组长度,使得最大值停留在
//当前数组的末尾.
//3 当之前数据末尾数据移到二叉堆顶端后,二叉堆可能失去了原来的性质,此时需要从二
//叉堆顶部重新进行下沉处理,使得数组剩余数据再次构成二叉堆特性.
//4 重复步骤2~3,省得从二叉堆中依次取出最大值,并倒序放置到数组中,最终形成降序排序
void sort(int iArray[], int count)
{
int k = 0;

//将原数组数据构造成二叉堆,从数组最后索引开始进行下沉处理来构造二叉堆,
//之后数组索引不断进行递减,使得最终从顶端索引1进行下沉处理来完成最终的二叉
//堆构造
//k = count / 2,这里是为了跳过叶子节点,如上图示例,叶子节点4\5\6\7下面已经没
//有子节点了,所以不需要进行下沉处理.
//k >= 1,是因为当前采用数组方式存储二叉堆,为了计算父子索引方便,数组索引0不
//使用,直接从索引1开始.
for ( k = count / 2; k >= 1; k-- )
{
sink(iArray, count, k);
}

//开始进行堆排序处理
//count > 2,是因为当前不使用数组0索引,所以如果二叉堆中至少需要2个数据进行
//排序处理,则至少数组长度应该大于2
while ( count > 2 )
{
count--;
//将二叉堆顶部索引1的数值与当前数组末尾的值进行交换
exch(iArray, count, 1);
//数组末尾的值交换到二叉堆顶端后,从顶端开始进行下沉处理,保证二叉堆的
//特性有效
sink(iArray, count, 1);
}
}

//二叉堆的特性就是每个节点的数值都大于子节点的数值
//当新加或删除节点后,就要重新进行处理,来保证二叉堆的特性不变,这
//里的算法是属于下降方式处理,其思想如下:
//1 首先判断当前节点下还有子节点
//2 从左叶子节点及右叶子节点中选择一个最大的值
//3 使用该值与当前节点进行比较,因为当前节点是叶子节点的父节点,所以
//  按二叉堆的特性,该节点应该不能小于叶子节点,如果该节点大于叶子节
//  点,则满足二叉堆特性,退出处理,否则需要将此节点与最大的叶子节点
//  值进行交换
//4 如果在第3步中发生了交换,则当前新值已经移到了最大叶子节点的位置
//  ,此时需要继续检查当前位置的值是否大于当前索引下的叶子节点,处理
//  方法同第1~3步相同
void sink(int iArray[], int count, int k)
{
//至少存在左叶子节点
while ( 2 * k < count )
{
//左叶子节点索引值
int leaf = 2 * k;

//如果存在右叶子节点, 则从两个叶子节点中挑出一个
//最大值的叶子索引
if ( leaf + 1 < count )
{
if ( less(iArray[leaf],  iArray[leaf + 1]) )
{
leaf++;
}
}

//如果当前父节点大于等于最大的叶子节点,则已经满足二叉堆
//特性,退出处理
if ( !less(iArray[k], iArray[leaf]) )
{
break;
}

//当前父节点小于叶子节点,则进行父节点和叶子节点的数据交换
exch(iArray, k, leaf);

//当前待处理的数据已经移到了最大的叶子节点位置,此时需要将
//当前索引更改为替换后的叶子索引位置,用于继续当前数据
//与下一叶子值的比较处理
k = leaf;
}
}

int main()
{
int iArray[] = {-1, 2, 5, 6, 1, 8, 3, 9, 4, 3, 1, 7};

sort(iArray, 12);
arrayShow(iArray, 12);

return 0;
}


#include <stdio.h>
#include "util.h"

void arrayShow(int iArray[], int size)
{
int i = 0;

for ( i = 0; i < size; i++ )
{
printf("%d ", iArray[i]);
}
printf("\r\n");
}

int less(int a, int b)
{
if ( a < b ) return 1;
return 0;
}

int compare(int a, int b)
{
if ( a > b ) return 1;
if ( a < b ) return -1;
return 0;
}

void exch(int iArray[], int indexA, int indexB)
{
int tmp = iArray[indexA];
iArray[indexA] = iArray[indexB];
iArray[indexB] = tmp;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: