堆排序
堆排序(Heapsort)是指利用堆(Heap)这种数据结构所设计的一种排序算法。
堆是一个近似完全二叉树的结构,且有两种性质的堆:
- 大顶堆:每个结点的值都大于其左孩子和右孩子结点的值 ,用于
升序排列
; - 小顶堆:每个结点的值都小于其左孩子和右孩子结点的值 ,用于
降序排列
。
因为堆顶的值是存放在数组最后的
下标为i的节点:
- 父节点下标:(i - 1) / 2 [整除法]
- 左孩子下标 :i * 2 + 1
- 右孩子下标:i * 2 + 2
大顶堆:
算法步骤
- 创建一个大顶堆,主要通过heapify函数:通过父节点,找到它的左子和右子,将左子和右子的最大值和父节点比较,如果大于父节点就进行交换。
- 进行堆排序,交换堆首和堆尾 swap(arr[0], arr[i]),大顶堆的堆首一定是最大的值,交换后大顶堆就被破坏了,因此维护剩下的堆的性质 :heapify(arr, 0, i - 1),重复这个过程。
代码实现
#include <iostream>
#include <algorithm>
using namespace std;
//建立大顶堆
void heapify(int arr[], int start, int end)
{
// 建立父指针和孩子指针
int dad = start;
int son = dad * 2 + 1;
while (son <= end)
{
if (son + 1 <= end && arr[son] < arr[son + 1]) // son代表左孩子和右孩子中更大的那个
son++;
if (arr[dad] > arr[son]) // 代表调整完毕
return;
else
{ // 交换父亲和儿子节点的值
swap(arr[dad], arr[son]);
dad = son;
son = dad * 2 + 1;
}
}
}
void heap_sort(int arr[], int len)
{
//由无序堆建立大顶堆
// i = len / 2 - 1是下标为 i 的节点的父节点的下标
for (int i = len / 2 - 1; i >= 0; i--)
heapify(arr, i, len - 1);
//此时arr[0]就是最大的值,将它与最末位arr[i]交换,对剩下的i-1个元素递归使用堆排序
for (int i = len - 1; i > 0; i--)
{
swap(arr[0], arr[i]);
//交换后大顶堆被破坏,维护大顶堆的性质
heapify(arr, 0, i - 1);
}
}
int main()
{
int arr[] = {16, 4, 10, 14, 7, 9, 3, 2, 8, 1};
int len = (int)sizeof(arr) / sizeof(*arr);
heap_sort(arr, len);
for (int i = 0; i < len; i++)
cout << arr[i] << endl;
return 0;
}