堆排序--图解

本文详细解析了大顶堆的构造与调整过程,通过具体实例展示了如何通过比较和交换元素来构建大顶堆,并逐步调整堆以实现排序。文章深入探讨了堆排序算法的核心原理,包括初始化大顶堆、调整堆以及最终的排序过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大堆顶                                                                        小堆顶

构造堆

在构造有序堆时,我们开始只需要扫描一半的元素(n/2-1 ~ 0)即可,为什么?

因为(n/2-1)~0的节点才有子节点,如图1,n=8,(n/2-1) = 3  即3 2 1 0这个四个节点才有子节点

 

所以代码4~6行for循环的作用就是将3 2 1 0这四个节点从下到上,从右到左的与它自己的子节点比较并调整最终形成大顶堆,过程如下:

 

第一次for循环将节点3和它的子节点7 8的元素进行比较,最大者作为父节点(即元素60作为父节点)

【红色表示交换后的状态】

第二次for循环将节点2和它的子节点5 6的元素进行比较,最大者为父节点(元素80作为父节点)

第三次for循环将节点1和它的子节点3 4的元素进行比较,最大者为父节点(元素70作为父节点)

第四次for循环将节点0和它的子节点1 2的元素进行比较,最大者为父节点(元素80作为父节点)

(注意这里,元素20和元素80交换后,20所在的节点还有子节点,所以还要再和它的子节点5 6的元素进行比较,这就是28行代码 i = j 的原因)

至此有序堆已经构造好了!如下图:

调整堆

下面进行while循环

(1)堆顶元素80和尾40交换后-->调整堆

(2)堆顶元素70和尾30交换后-->调整堆

(3)堆顶元素60尾元素20交换后-->调整堆

(4)其他依次类推,最终已排好序的元素如下:

 

#include<stdio.h>
 
int c=0;
 
/*heapadjust()函数的功能是实现从a[m]到a[n]的数据进行调整,使其满足大顶堆的特性*/
/*a[]是待处理的数组,m是起始坐标, n是终止坐标*/
void heapadjust(int a[], int m, int n)
{
    int i, temp;
    temp=a[m];
 
    for(i=2*m;i<=n;i*=2)//从m的左孩子开始
    {
        if(i+1<=n && a[i]<a[i+1])//如果左孩子小于右孩子,则将i++,这样i的值就是最大孩子的下标值
        {
            i++;
        }
 
        if(a[i]<temp)//如果最大的孩子小于temp,则不做任何操作,退出循环;否则交换a[m]和a[i]的值,将最大值放到a[i]处
        {
            break;
        }
        a[m]=a[i];
        m=i;
    }
    a[m]=temp;
}
 
void crtheap(int a[], int n)//初始化创建一个大顶堆
{
    int i;
    for(i=n/2; i>0; i--)//n/2为最后一个双亲节点,依次向前建立大顶堆
    {
        heapadjust(a, i, n);
    }
}
 
/*swap()函数的作用是将a[i]和a[j]互换*/
void swap(int a[], int i, int j)
{
    int temp;
    temp=a[i];
    a[i]=a[j];
    a[j]=temp;
    c++;
}
 
void heapsort(int a[], int n)
{
    int i;
 
    crtheap(a, n);
    for(i=n; i>1; i--)
    {
        swap(a, 1, i);//将第一个数,也就是从a[1]到a[i]中的最大的数,放到a[i]的位置
        heapadjust(a, 1, i-1);//对剩下的a[1]到a[i-1],再次进行堆排序,选出最大的值,放到a[1]的位置
    }
}
 
int main(void)
{
    int i;
    int a[10];
	printf("任意输入10个数:");
	for(i=0;i<10;i++)
	{
		scanf("%d",&a[i]);
	}
    printf("排序前:");
    for(i=1;i<10;i++)
    {
        printf("%d",a[i]);
    }
    heapsort(a, 9);
    printf("\n\n共交换数据%d次\n\n", c);
    printf("排序后:");
    for(i=1;i<10;i++)
    {
        printf("%d",a[i]);
    }
    printf("\n\n\n");
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值