基本思想:
堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n - 1个元素重新构造成一个堆,这样会得到n个元素的次大值,并与n - 1位置的元素再进行交换,此时n - 1位置就为次大值。如此反复执行,便能得到一个有序序列了
图解:
时间复杂度:O(nlog2n)
空间复杂度:O(1)
稳定性:不稳定
堆调整算法
首先将所有元素构建成为初始大根堆
建初始堆结束后,顶元素为最大元素,将其与最后一个元素互换,这样最后一个元素为最大,已经有序
之后除去有序元素,对无序元素再进行堆调整,将无序构成大根堆
这样调整后顶元素就是无序元素中的最大值,所有元素中的次大值
在将其于除去有序元素的尾部元素交换,这样所有元素中最大的两个元素已经在末尾排好
代码
/*大根堆算法实现
** 若元素下标为 s ,则在完全二叉树中其左孩子结点为 2 * s + 1
** 每次交换元素后,都要判断该修改元素位置是否有孩子节点,若有要继续判断大小
*/
void HeapAdjust(int *arr, int start, int end)
{
int tmp = arr[start];
for (int i = start * 2 + 1; i < end; i = i * 2 + 1)
{
if (i < end - 1 && arr[i] < arr[i + 1])
{
i++;
}
if (arr[i] > arr[start])
{
arr[start] = arr[i];
start = i;
}
else
{
break;
}
arr[start] = tmp;
}
}
/* 堆调整算法
** 首先将所有元素构建成为初始大根堆
** 建初始堆结束后,顶元素为最大元素,将其与最后一个元素互换,这样最后一个元素为最大,已经有序
** 之后除去有序元素,对无序元素再进行堆调整,将无序构成大根堆
** 这样调整后顶元素就是无序元素中的最大值,所有元素中的次大值
** 在将其于除去有序元素的尾部元素交换,这样所有元素中最大的两个元素已经在末尾排好
*/
void HeapSort(int *arr, int len)
{
int i;
for (i = (len - 1) / 2; i >= 0; i--) // 将所有数据建立大根堆
{
HeapAdjust(arr, i, len);
}
/*
** 每次将最后一个元素与顶元素互换,确保每次末尾元素都是最大
** 每次互换完毕后,最后一个元素已经有序,除去有序元素,其余元素要重新调整成大根堆
*/
for (i = len - 1; i > 0; i--)
{
int tmp = arr[0];
arr[0] = arr[i];
arr[i] = tmp;
HeapAdjust(arr, 0, i);
}