《大话数据结构》之堆排序

本文详细介绍了基于完全二叉树实现的堆排序算法,包括大顶堆和小顶堆的概念,以及如何通过调整节点位置来保持堆的性质。通过具体的C语言代码示例,展示了如何构建和调整堆,并最终完成排序过程。

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

所谓的堆,实际是排序后的完全二叉树。

完成这个算法需要掌握排序后的完全二叉树的一些特性:

1、按层数,从上往下,依次为第一层,第二层,。。。,第n+1层。第n层的数据,一定大于(大顶堆)或小于(小顶堆)第n+1层的数据。

2、如果对一棵有n个节点的完全二叉树(其深度为不大于㏒2ⁿ的最大整数+1)的节点按层序编号(从1到不大于㏒2ⁿ的最大整数+1层,每层从左到右),对任一节点(1≤i≤n)有

   2.1、如果i=1,则节点i是二叉树的根,无双亲,如果i>1,则其双亲是节点 不大于i/2的最大整数
   2.2、如果2i>n,则节点i无左孩子;否则其左孩子是节点2i
   2.3、如果2i+1>n,则i节点无右孩子,否则其右孩子是节点2i+1

知道了上面这些特性,才有办法理解代码中的逻辑循环。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_LEN 256
typedef struct
{
	int iInput[MAX_LEN];
	int iLength;
}SqArr;

void swap(SqArr *pToSwap,int iFirst,int iSecond)
{
	if (iFirst != iSecond)
	{
		pToSwap->iInput[iFirst] = pToSwap->iInput[iFirst] + pToSwap->iInput[iSecond];
		pToSwap->iInput[iSecond] = pToSwap->iInput[iFirst] - pToSwap->iInput[iSecond];
		pToSwap->iInput[iFirst] = pToSwap->iInput[iFirst] - pToSwap->iInput[iSecond];
	}
}

int Output(SqArr *pSqToPrint)
{
	int iLoop;
	for(iLoop=1;iLoop<=pSqToPrint->iLength;iLoop++)
	{
		printf("%d ",pSqToPrint->iInput[iLoop]);
	}
	printf("\n");
	return 0;
}

void HeapAdjust(SqArr *pToSort,int iStart,int iEnd)
{
	int iLoop;
	for(iLoop=iStart*2;iLoop<=iEnd;iLoop=iLoop*2)
	{
		/*判断左子节点和右子节点哪个更小*/
		if((iLoop+1)<=iEnd)
		{
			if(pToSort->iInput[iLoop+1]<pToSort->iInput[iLoop] )
			{
				iLoop = iLoop + 1;
			}
		}
		/*
		如果父节点已经小于最小的子节点,则没有必要再循环
		*/
		if(iLoop<=iEnd && pToSort->iInput[iStart] < pToSort->iInput[iLoop])
		{
			break;
		}
		swap(pToSort,iStart,iLoop);
		iStart = iLoop;
	}
}

int HeapSort(SqArr *pToSort)
{
	int iLoop;
	int iLength;
	iLength = pToSort->iLength;

	for(iLoop = iLength/2;iLoop>=1;iLoop--)
	{
		HeapAdjust(pToSort,iLoop,iLength);
	}
	
	printf("排序结果为:\n");
	for(iLoop=1;iLoop<=iLength;iLoop++)
	{
		printf("%d ",pToSort->iInput[1]);
		swap(pToSort,1,iLength-(iLoop-1));
		HeapAdjust(pToSort,1,iLength-iLoop);
	}
	printf("\n");
	return 0;
}

int main()
{
	char strInput[MAX_LEN];
	char *pStrInput = NULL;
	char *pStrtok = NULL;
	int iLoop;
	SqArr iToSort;

	memset(strInput,0x00,sizeof(strInput));
	memset(&iToSort,0x00,sizeof(SqArr));

	printf("%s","请输入待排序数据,以逗号分隔,以回车结束:\n");
	scanf("%s",&strInput);
	pStrInput = strInput;

	for(iLoop=1;;iLoop++,pStrInput=NULL)
	{
		pStrtok = strtok(pStrInput,",\n");
		if(NULL == pStrtok)
		{
			break;	
		}
		iToSort.iInput[iLoop] = atoi(pStrtok);
		iToSort.iLength = iLoop;
	}
	
	HeapSort(&iToSort);

	getchar();
	return 0;
}


这个算法有个很蛋疼的情况:按数组存储,最后输出的话是不能按数组下标输出的,因为他虽然是排序的完全二叉树,但又并不保证左子节点最小,或者是右子节点最小,只能确认按层次,上一层一定比下一层小(或大)。
所以在输出最后排序结果时,仍然需要不断的重新调整。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值