堆排序

    堆是一种完全二叉树结构,并且其满足一种性质:父节点存储值大于(或小于)其孩子节点存储值,分别称为大顶堆、小顶堆。堆一般采用数组进行存储(从下标为1开始),则父节点位置为i,那么其左孩子为2*i,右孩子为2*i + 1。

一. 算法描述

堆排序主要分为两个过程:

(1)先使长度为N数组形成一个N个节点组成的大顶堆

(2)然后将堆顶数据与末尾数据交换,再对N-1长的堆调整为大顶堆;反复进行,直到堆节点数为1结束堆排序。

从无序数组形成大顶堆过程如下图所示:


大顶的堆的形成要由下到上,子节点先形成大顶堆后,再考虑父节点,这样做逻辑比较清晰;形成大顶堆后在按照步骤2就可以完成堆排序。

二. 算法分析

平均时间复杂度:O(nlog2n)

空间复杂度:O(1) (用于交换数据) 

稳定性:不稳定

三. 算法实现

//交换data1和data2所指向的整形
void DataSwap(int* data1, int* data2)
{
	int temp = *data1;
	*data1 = *data2;
	*data2 = temp;
}


/********************************************************
*函数名称:SlipDown
*参数说明:pDataArray 无序数组;
*		   iCurNode为堆中需要调整的节点
*          iDataNum为数组长度
*函数返回:分割后的分割数位置
*函数说明:调整iCurNode处的节点,形成大顶堆    
*********************************************************/
void SlipDown(int *pDataArray,int iCurNode,int iDataNum)
{
	int temp = pDataArray[iCurNode];    //记录需要调整的节点值

	for (int iNextNode = iCurNode*2; iNextNode <= iDataNum; iNextNode = iCurNode*2)
	{
		if (iNextNode + 1 <= iDataNum 
			&& pDataArray[iNextNode] < pDataArray[iNextNode + 1])    //寻找iCurNode子节点中的大者
			iNextNode++;
		if (pDataArray[iNextNode] > temp)    //大的值上移
			pDataArray[iCurNode] = pDataArray[iNextNode];    
		else    //结束调整
			break;

		iCurNode = iNextNode;    //更新需要调整的节点
	}

	pDataArray[iCurNode] = temp;
}

/********************************************************
*函数名称:HeapSort
*参数说明:pDataArray 无序数组;
*		   iDataNum为无序数据个数
*说明:    堆排序
*********************************************************/
void HeapSort(int* pDataArray, int iDataNum)
{
	pDataArray--;    //让原先数组下标0对应1,便于堆中节点的访问
	for (int i = iDataNum/2; i > 0; i--)    //调整为大顶堆
		SlipDown(pDataArray, i, iDataNum);

	for (int i = iDataNum; i > 1; i--)    //根据大顶堆进行排序
	{
		DataSwap(&pDataArray[i], &pDataArray[1]);
		SlipDown(pDataArray, 1, i - 1);
	}
}



补充:

排序算法不少人写过,目前为止我看过的最系统的还属维基百科的排序算法,截图为证(图中红色字体表示维基还没有创建这个词条,各位有兴趣可以去做下贡献哦)。


  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值