小顶堆排序C语言,堆排序原理 C语言实现堆排序及过程详解

堆排序就是把最大堆堆顶的最大数取出,将剩余的堆继续调整为最大堆,再次将堆顶的最大数取出(最大堆调整的递归运算),这个过程持续到剩余数只有一个时结束。在堆中定义以下几种操作:

最大堆调整(Max-Heapify):

将堆的末端子节点作调整,使得子节点永远小于父节点

创建最大堆(Build-Max-Heap):

将堆所有数据重新排序,使其成为最大堆

堆排序(Heap-Sort):

移除位在第一个数据的根节点,并做最大堆调整的递归运算

继续进行下面的讨论前,需要注意的一个问题是:数组都是 Zero-Based,这就意味着我们的堆数据结构模型要发生改变

ab76a305c656?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

heap-and-array-zero-based.png

相应的,几个计算公式也要作出相应调整:

Parent(i) = floor((i-1)/2),i 的父节点下标

Left(i) = 2i + 1,i 的左子节点下标

Right(i) = 2(i + 1),i 的右子节点下标

最大堆调整(MAX‐HEAPIFY)的作用是保持最大堆的性质,是创建最大堆的核心子程序,作用过程如图所示:

ab76a305c656?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

max‐heapify-procedure.png

创建最大堆(Build-Max-Heap)的作用是将一个数组改造成一个最大堆,接受数组和堆大小两个参数,Build-Max-Heap 将自下而上的调用 Max-Heapify 来改造数组,建立最大堆。因为 Max-Heapify 能够保证下标 i 的结点之后结点都满足最大堆的性质,所以自下而上的调用 Max-Heapify 能够在改造过程中保持这一性质。如果最大堆的数量元素是 n,那么 Build-Max-Heap 从 Parent(n) 开始,往上依次调用 Max-Heapify。流程如下

ab76a305c656?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

building-a-heap.png

堆排序(Heap-Sort)是堆排序的接口算法,Heap-Sort先调用Build-Max-Heap将数组改造为最大堆,然后将堆顶和堆底元素交换,之后将底部上升,最后重新调用Max-Heapify保持最大堆性质。由于堆顶元素必然是堆中最大的元素,所以一次操作之后,堆中存在的最大元素被分离出堆,重复n-1次之后,数组排列完毕。整个流程如下:

ab76a305c656?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

HeapSort.png

C语言实现:

#include

#include

void swap(int *arr,int i, int k)

{

int temp = arr[i];

arr[i] = arr[k];

arr[k] = temp;

}

void max_heapify(int *arr, int start, int end)

{

//建立父节点下标和子节点下标

int dad = start;

int son = dad * 2 + 1;

while (son <= end)

{ //若子节点下标在范围内才做比较

if (son + 1 <= end && arr[son] < arr[son + 1]) //先比较两个子节点大小,选择最大的

{

son++;

}

if (arr[dad] > arr[son]) //如果父节点大于子节点代表调整完毕,直接跳出

{

return;

}

else

{ //否则交换父子节点的值再继续左右子节点值得比较

swap(arr,dad, son);

printf("dad=%d--son=%d\n",dad,son);

dad = son;

son = dad * 2 + 1;

}

}

}

void heap_sort(int *arr, int len)

{

int i;

//初始化,i从最后一个父节点开始调整

for (i = len / 2 - 1; i >= 0; i--)

{

max_heapify(arr, i, len - 1);

}

for (i = len - 1; i > 0; i--)

{

swap(arr,0, i);

max_heapify(arr, 0, i - 1);

}

}

int main(int argc, char const *argv[])

{

int arr[] = {5,3,8,1,6};

int len = sizeof(arr) / sizeof(int);

heap_sort(arr, len);

for (int i = 0; i < len; i++)

{

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

}

printf("\n");

return 0;

}

步骤详解:

下标0 1 2 3 4

数组5 3 8 1 6

ab76a305c656?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

001.png

Array={5,3,8,1,6};

Len=5

i=5/2 -1 =1 为最后一个元素的父节点的下标值

Max_heapity(arr,i,len-1)

i=1 len-1=4 end=4

1 > 6 son=4

第一次交换3和6值

ab76a305c656?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

002.png

dad=4

son=4*2+1=9

9>4 while 第一次结束

i=0

Max_heapity(arr,0,4)

dad=0 ; end=4 son=1

1 < 4

6< 8

son=2

第二次 交换5和8值(此时为最大堆)

ab76a305c656?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

003.png

dad=2

son=2*2 +1 =5

5

i=-1 i<0 第一个for循环结束

第二个for循环开始

len=5

i=len-1=4

swap(arr,0,4)

ab76a305c656?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

004.png

max_heapity(arr,0,3)

dad=0 son=1 end=3

swap(arr,0,1)

ab76a305c656?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

005.png

son=3 dad=1

while 第三次结束

i=3 len=5

swap(arr,0,3)

ab76a305c656?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

006.png

max_heapify(arr,0,2);

dad=0; son=1;end=2

3 < 5

son=2

swap(arr,0,2);

ab76a305c656?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

007.png

dad=2

son=2*2+1=5

while 第四次结束

i=2 len=5

swap(arr,0,2)

ab76a305c656?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

008.png

max_heapity(arr,0,1)

dad=0; son=1 end=1

swap(arr,0,1);

ab76a305c656?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

009.png

i=1 len=5

max_heapity(arr,0,0)

dad=0; son =1

1<0 while跳出

最后堆顶的最大数3取出 再取出1

ab76a305c656?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

010.png

i=0时 第二个for循序结束

最终结果: 13 5 6 8

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值