堆排序算法得核心思想是:
1 将待排序序列构造成堆得形式
2 每次将堆顶和末尾空间交换值,然后再重新调整被破坏得堆结构。
大致实现步骤:
1 先从最后的非叶子节点开始构建最小得堆,然后再从下向上构建整个堆结构
2 交换并调整堆结构
代码实现如下:
void Swap(int* param1, int* param2)
{
int tmpValue = *param1;
*param1 = *param2;
*param2 = tmpValue;
}
//将子树构造成堆
void ChildTreeToHeap(int* array, int rootIndex, int endIndex)
{
int dadIndex = rootIndex;
int SonIndex = dadIndex * 2 + 1;
//从根节点从上到下得构建堆,该情况只会比较直接父节点和子节点得大小关系,
//不会比较孙子节点和父节点得大小关系。
//所以如果以此方式构建堆,前提得保证原先得子树就是堆结构。
//此处就能看出 为什么在堆排序前 先从length /2 -1为根节点得地方构建一个堆得原因了。
while (SonIndex <= endIndex)
{
if (SonIndex + 1 <= endIndex && array[SonIndex] < array[SonIndex + 1])
SonIndex++;
if (array[dadIndex] < array[SonIndex])
{
Swap(&array[dadIndex], &array[SonIndex]);
dadIndex = SonIndex;
SonIndex = dadIndex * 2 + 1;
}
else
{
return;
}
}
}
void HeapSoft(int* array, int length)
{
//1 先从 最后的非叶子节点开始 建立一个最大堆,
for (int i = length / 2 - 1; i >= 0; i--)
{
//此处的i 是子树的根节点,length / 2 - 1 是最后的那个子树的根节点下标
ChildTreeToHeap(array, i, length - 1);
}
//此时已经构造了一个堆
for (int i = length - 1; i > 0; i--)
{
Swap(&array[0], &array[i]);
//此处堆结构被破坏,所以得重新在原来得基础上构建。
ChildTreeToHeap(array, 0, i - 1);
}
}
堆排序算法分析:
1 在构建整个堆得过程中,将待排序得序列转换成完全二叉树的形式。
2 比较过程先从左右得最小子树开始,有效得避免了更多的构造堆过程中得回溯比较过程。
3 将整个序列分成了左右子树两部分,并分开比较,避免了许多无谓得比较。
4 每次交换得过程中 ,只破环了树中一部分子树得堆结构,再次调整堆的时候就避免了,不必要的比较。
注:
谨记每一次元素的交换都有可能造成,堆结构的破坏所以在每一次产生了交换,就得重新调整成堆结构。 这样才能形成以后的比较次数更少。
堆排序不是稳定的排序。
堆排序的时间复杂度:O (nlgn)