堆是一种完全二叉树结构,并且其满足一种性质:父节点存储值大于(或小于)其孩子节点存储值,分别称为大顶堆、小顶堆。堆一般采用数组进行存储(从下标为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);
}
}
补充:
排序算法不少人写过,目前为止我看过的最系统的还属维基百科的排序算法,截图为证(图中红色字体表示维基还没有创建这个词条,各位有兴趣可以去做下贡献哦)。

1万+

被折叠的 条评论
为什么被折叠?



