HeapSort
堆排序是基于堆上的一种排序方法,数据存储的结构是数组,该排序的效率接近排序的下界nlog(n)。
学习堆排序前最好理解掌握以下内容
- 二叉树
- 二叉堆
- 最大堆与最小堆概念
这些概念可以自行百度或谷歌,要留意这里”堆”的概念不同于c++里分配内存所说的堆;
堆排序算法原理如下(基于最大堆而言的):
- 将长度为n的待排序的数组进行堆有序化构造成一个大顶堆(初始最大堆的构建)
- 将根节点与尾节点交换
- 将剩余的n -1个节点重新进行堆有序化
- 重复步骤2,步骤3直至构造成一个有序序列
总而言之,该算法的思想就是最大堆堆顶的最大数取出,将剩余的堆继续调整为最大堆,再次将堆顶的最大数取出,这个过程持续到剩余数只有一个时结束(有点像选择排序那样每次抽出剩余数据的最大值)
第一步:构造堆(Build_Max_Heap):初始化构造堆所形成的二叉树有点类似于完全二叉树,比如如果树的高度为H,那么前H-1层对应的节点数必须是2^(H-1);第H层必须排满树的左边才能排右边。初始化好后堆节点的访问如下:
在数组起始位置为0的情形中:
1. 父节点i的左子节点在位置 2i+1;
2.父节点i的右子节点在位置 2i+2;
3.子节点i的父节点在位置 (i-1)/2;
// 一开始构建好二叉堆(满足最大堆的特征);
void buildHeap(int *arr, int size)
{
for (int i = (size - 1) / 2; i >= 0; i--)
{
//传入给max_heapify_once 后两个参数为数组的下标;
max_heapify_once(arr, i, size - 1);
}
}
2.最大堆调整(Max_Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点
void max_heapify_once(int* arr, int start, int end)
{
int father = start;
int son = start * 2 + 1;//左子节点是父子节点的下标*2+1;
while (son <= end)
{
if (son + 1 <= end && arr[son + 1] > arr[son]) //如果右子节点存在并且大于左子节点的情况;
{
son++;
}
//如果父节点小于两个子节点中最大者就与其交换,这样就会改变该子节点下面的最大堆结构,所以要继续做下去;
else if (arr[father] < arr[son])
{
swap(arr[father], arr[son]);
father = son;
son = father * 2 + 1;
}
else //如果父子节点比两个子节点都大直接退出函数,因为子节点下面的子节点已满足最大堆的特征
{
return;
}
}
}
3.堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整
void heapSort(int* arr, int size)
{
buildHeap(arr, size);
for (int i = size - 1; i > 0; i--)
{
swap(arr[0], arr[i]);
max_heapify_once(arr, 0, i-1);
}
}
总的代码如下:
#include <iostream>
#include <algorithm>
using std::swap;
using std::cout;
using std::endl;
using std::cin;
void max_heapify_once(int* arr, int start, int end)
{
int father = start;
int son = start * 2 + 1;//左子节点是父子节点的下标*2+1;
while (son <= end)
{
if (son + 1 <= end && arr[son + 1] > arr[son]) //如果右子节点存在并且大于左子节点的情况;
{
son++;
}
//如果父节点小于两个子节点中最大者就与其交换,这样就会改变该子节点下面的最大堆结构,所以要继续做下去;
else if (arr[father] < arr[son])
{
swap(arr[father], arr[son]);
father = son;
son = father * 2 + 1;
}
else //如果父子节点比两个子节点都大直接退出函数,因为子节点下面的子节点已满足最大堆的特征
{
return;
}
}
}
// 一开始构建好二叉堆(满足最大堆的特征);
void buildHeap(int *arr, int size)
{
for (int i = (size - 1) / 2; i >= 0; i--)
{
//传入给max_heapify_once 后两个参数为数组的下标;
max_heapify_once(arr, i, size - 1);
}
}
void heapSort(int* arr, int size)
{
buildHeap(arr, size);
for (int i = size - 1; i > 0; i--)
{
swap(arr[0], arr[i]);
max_heapify_once(arr, 0, i-1);
}
}
int main()
{
int n;
cout << "Please enter the sum of number you want to sort with heap sort: ";
cin >> n;
int * arr = new int[n];
for (int i = 0; i < n; i++)
{
cin >> arr[i];
}
heapSort(arr, n);
for (int i = 0; i < n; i++)
{
cout << arr[i] << ' ';
}
cout << endl;
delete[] arr;
system("pause");
return 0;
}