c语言排序算法_堆排序算法 -- C语言

算法原理

堆排序定义:

n个序列 Al, A2,…, An 称为堆,有下面两种不同类型的堆。

  • 小根堆:所有子结点都大于其父节点,即 Ai ≤ A2i 且 Ai ≤ A2i+ 1。
  • 大根堆: 所有子结点都小于其父节点,即 Ai ≥ A2i 且 Ai ≥ A2i+ 1。

(数组是从0开始计算的,为了平衡考虑,使用 A2i + 1 和 A2i + 2)

若将此序列所存储的向量 A[ 1... n] 看为一棵完全二叉树的存储结构,则堆实质上是满足如下性质的完全二叉树:树中任一非叶结点的关键字均不大于(或不小于)其左、右的节点(若存在)的关键字。

因此堆排序(HeapSort) 是树形选择排序。在排序过程中,将 R[l... n] 看成一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系,在当前无序区中选择关键字最大(或 最小)的 记录。

用大根堆排序的基本思想:

(1) 先将初始 A[1... n] 建成一个大根堆,此堆为初始的无序 区。

(2) 再将关键字最大的记录 A[1](堆顶)和无序区的最后一个记录 A[n] 交换,由此得到新的无序区A[1... n-1] 和有序区 A[n],且满足 A[1... n- 1] ≤ A[n]。

(3) 由于交换后新的根A[1]可能违反堆性质,故应将当前无序区 A[1... n- 1] 调整为堆。然后再次将 A[1... n-1] 中 关键字最大的记录 A[1] 和该区间的最后一个记录 A[n- 1] 交换,由此得到新的无序区 A[1... n- 2] 和有序区 A[ n-1... n],且仍满足关系 A[ 1... n-2] ≤ A[n- 1... n],同样要将 A[1... n- 2] 调整为 堆。

(4) 对调整的堆重复进行上面的交换,直到无序区只有一个元素为止。

构造初始堆必须用到调整堆的操作,现在说明 Heapify 函数思想方法。

每趟排序开始前,A[l… i] 是以 A[1] 为根的堆,在 A[1] 与 A[i] 交换 后,新的无序区 A[1… i-1]中只有A[1] 的值发生了变化,故除 A[1] 可能违反堆性质外,其余任何结点为根 的子树均是堆。因此,当被调整区间是 A[ low… high] 时,只须调整以 A[low] 为根的树即可。

可以使用“ 筛选法” 进行堆的调整。 A[low] 的 左、 右 子树(若 存在)均已是堆,这两棵子树的根 A[ 2low] 和 A[ 2low+ 1] 分别是各自子树中关键字最大的节点。 若 A[low] 不小于这两个孩子节点的关键字,则A[low]未违反堆性质,以 A[low] 为根的树已是堆,无须调整;否则必须将 A[low] 和它的两个孩子节点中关键字较大者进行交换,即 A[low] 与 A[large] (A[large]= max( A[2low],A[2low+ 1]))交换。交换后又可能使节点 A[large] 违反堆性质。同样,由于该节点的两棵子树(若存在)仍然是堆,故可重复上述调整过程,对以 A[large] 为根的树进行调整。此过程直至当前被调整的节点已满足堆性质,或者该节点已是叶子为止。上述过程就像过筛子一样,把较小的关键字逐层筛下去,而将较大的关键字逐层选上来。

算法草稿

2b5416ac826cf5dfdce8fc91a24dccba.png

堆排序算法草稿

代码实现

#include

#include

#define SUCCESS0

#define PARAM_ERR-1

int BuildMaxHeap(int * array, int low, int high){

if(NULL == array){

printf("%s para error", __func__);

return PARAM_ERR;

}

//printf("Enter BuildMaxHeap low = %d, high = %d", low, high);

int left = 0, right = 0; /*子树的索引*/

int max = low; /*最大子节点的索引,默认[low]是堆的根 */

int temp = 0;

/*

* low 是根堆,默认[low] 是最大的点做在的位置

* 不用 2 * low 和 2 * low + 1, 是因为对于0为根的对来说,子树就都在右边了,树就不平生了

* left = 2 * low;

* right = 2 * low + 1;

* 当然,这么用也没什么错误,就是树不太平衡,像个瘸子 ;-D

*/

left = 2 * low + 1;

right = 2 * low + 2;

/*

* 有左子节点 且 [low] 不是最大节点,max取得左子树

* 注意比较前,需要保证左子节点存在:left <= high

*/

if((left <= high) && (array[left] > array[low])){

max = left;

} else {

max = low;

}

/*

* 有右子节点 且 [low] 不是最大节点,max取得左子树

* 注意比较前,需要保证左子节点存在:right <= high

*/

if((right <= high) && (array[right] > array[max])){

max = right;

}

if(max != low){

temp = array[max];

array[max] = array[low];

array[low] = temp;

/* 对交换的子树进行重新建堆*/

BuildMaxHeap(array, max, high);

}

//printf("Left BuildMaxHeap low = %d, high = %d", low, high);

return SUCCESS;

}

int initMaxHeap(int * array, int size){

if(NULL == array){

printf("%s para error", __func__);

return PARAM_ERR;

}

//printf("Enter initMaxHeap");

int i = 0;

#ifdef DEBUG

int k = 0;

#endif

/*

* 只是到 size /2 而不是 size,因为后半部分通过 2*i +1 和 2 * i + 2 子树方式完成了递归的构建

* 前半部分在初始化的时候,要逐个建堆

* for(i = size - 1; i >= 0; i--) 整个建堆也没有错,就是效率会差一些,随着数组越大,效率越差

* 注意要包含 0 和 size / 2 , 是个闭区间,不然少一个初次的建堆

* 还有一点非常重要,需要从后向前初始化,相当于需要先初始化好子树,再初始化父一级的树,这样才可以

* 反过来的初始化顺序是错误的,父一级错误,再初始化子一级也错误,二者就更加错误了

*/

for(i = size / 2; i >= 0; i--){

BuildMaxHeap(array, i, size - 1);

}

#ifdef DEBUG

printf("%s: size = %d", __func__, size);

printf("init Heap [");

for(k =0; k < size; k++){

printf(" %d ", array[k]);

}

printf("] ");

printf("");

#endif

//printf("Left initMaxHeap");

return SUCCESS;

}

int HeapSort(int * array, int size){

if(NULL == array){

printf("%s para error", __func__);

return PARAM_ERR;

}

int i = 0, j = 0;

int temp = 0;

#ifdef DEBUG

int k = 0;

#endif

//printf("Enter HeapSort");

/*初始化构建大根堆*/

initMaxHeap(array, size);

/* 每轮提取构建有序区,然后对新的无序区的堆再次平衡 */

for(i = size - 1 ; i > 0; i--){ /* 无序区逐步往前缩减,最后一个直接认为在有序区 */

/* 交换 [0] 和 [i], i 进入有序区*/

temp = array[0];

array[0] = array[i];

array[i] = temp;

#ifdef DEBUG

printf("heapsize = %d, [max] = %d, 已经swap([0], [%d]) ", i + 1, temp, i);

printf("[");

/*有序区域*/

for(k =0; k <= i; k++){

printf(" %d ", array[k]);

}

printf("] , ");

/*无序区域*/

printf(" [");

for(k = i + 1; k < size; k++){

printf(" %d ", array[k]);

}

printf("]");

printf("");

#endif

/* 构建堆 [0, i-1] */

BuildMaxHeap(array, 0, i - 1);

}

//printf("Left HeapSort");

return SUCCESS;

}

int main(int argc, char ** argv){

int array[10] = {7,3,5,8,0,9,1,2,4,6};

int i = 0;

printf("Before sort: ");

for(i = 0; i < 10; i++){

printf(" %d ", array[i]);

}

printf("");

HeapSort(array, 10);

printf("after sort: ");

for(i = 0; i < 10; i++){

printf(" %d ", array[i]);

}

printf("");

return 0;

}

调试编译

gcc HeapSort.c -DDEBUG

调试输出

Before sort:

7 3 5 8 0 9 1 2 4 6

initMaxHeap: size = 10

init Heap [ 9 8 7 4 6 5 1 2 3 0 ]

heapsize = 10, [max] = 9, 已经swap([0], [9])

[ 0 8 7 4 6 5 1 2 3 9 ] , []

heapsize = 9, [max] = 8, 已经swap([0], [8])

[ 3 6 7 4 0 5 1 2 8 ] , [ 9 ]

heapsize = 8, [max] = 7, 已经swap([0], [7])

[ 2 6 5 4 0 3 1 7 ] , [ 8 9 ]

heapsize = 7, [max] = 6, 已经swap([0], [6])

[ 1 4 5 2 0 3 6 ] , [ 7 8 9 ]

heapsize = 6, [max] = 5, 已经swap([0], [5])

[ 1 4 3 2 0 5 ] , [ 6 7 8 9 ]

heapsize = 5, [max] = 4, 已经swap([0], [4])

[ 0 2 3 1 4 ] , [ 5 6 7 8 9 ]

heapsize = 4, [max] = 3, 已经swap([0], [3])

[ 1 2 0 3 ] , [ 4 5 6 7 8 9 ]

heapsize = 3, [max] = 2, 已经swap([0], [2])

[ 0 1 2 ] , [ 3 4 5 6 7 8 9 ]

heapsize = 2, [max] = 1, 已经swap([0], [1])

[ 0 1 ] , [ 2 3 4 5 6 7 8 9 ]

after sort:

0 1 2 3 4 5 6 7 8 9

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值