堆排序
算法思维
堆排序也是一种选择排序,每次选出无序序列中一个最大或最小的元素并放到有序序列中去 因为堆排序是从后往前放的,所以升序要用大根堆,降序要用小根堆 堆排序在最坏的情况下时间复杂度也是
O
(
n
log
n
)
O(n \log n)
O ( n log n ) ,并且只需要一个辅助空间
算法设计
创建变量 i ,表示未排序序列的末尾 从未排序序列末尾开始,把未排序序列视作完全二叉树,从右往左,从下往上遍历每个非叶子节点,并对结构混乱(节点与其孩子比较,不是最大或最小)的结点进行调整(与最大或最小的孩子进行交换) 然后把推顶的元素与无序序列最后一个元素交换 未排序序列长度 i 减 1,重复2,直到整个序列有序
算法实现
// 堆排序
/*
mode: 非0:升序, 0:降序
*/
void sort_heapSort(int *arr, int len, int mode)
{
int i = len - 1;
int heap, judge_index;
while(i > 0)
{
// 从最后一个结点开始
for(int j = i; j > 0; j -=2)
{
// 找到双亲
heap = (j - 1) / 2;
// 找到要到堆顶的元素
if( (2*heap)+2 <= i )
{
// 如果有两个孩子节点
// 这里不能确定j是第一个孩子还是第二个孩子,所以直接用 heap 来当参数
judge_index = sort_judgeWithMode(arr[2*heap + 1], arr[2*heap + 2], mode) ? 2*heap + 2 : 2*heap + 1;
judge_index = sort_judgeWithMode(arr[heap], arr[judge_index], mode)? judge_index : heap;
}
else
{
// 因为堆是完全二叉树,所以只有一个孩子必是左孩子
judge_index = sort_judgeWithMode(arr[heap], arr[j], mode)? j: heap;
}
utils_exchange(arr, heap, judge_index);
}
// 堆顶元素放到未排序元素的最后
utils_exchange(arr, i, 0);
// 结点个数减1
i--;
}
}
运算结果
测试代码#define N 8
int main()
{
int arr[N] = {49,38,65,97,76,13,27,49};
printf("升序排列结果:\n");
sort_heapSort(arr, N, 1);
utils_print_arr(arr, N, "%d ");
printf("\n\n降序排列结果:\n");
sort_heapSort(arr, N, 0);
utils_print_arr(arr, N, "%d ");
return 0;
}
运算结果