什么是堆
堆是一个近似完全二叉树的结构,
并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
什么是堆排序
堆排序(英语:Heapsort)是指利用堆这种数据结构所设计的一种排序算法。
实现大顶堆
首先我们需要找到所有的非叶子结点,通过完全二叉树的性质我们知道
若父节点标号为n,则他的左结点为n×2,右结点为n×2+1
也就是说,当前所存储的最后一位数据的下标位置就是最后一个非叶子节点的孩子结点,逆推得出最后一个非叶子结点的下标为
[n = Arr.Length / 2
]
Arr是我们所存储数据的容器。
得到所有的非叶子结点后,我们需要对每一个非叶子结点和他的孩子结点进行比较大小,使它们都变成子大顶堆。
在上图中,我们能看出 55、68结点是非叶子结点,我们进行堆排序的时候是从下晚上进行堆排序。
首先,对55的节点和他的孩子结点进行排序,好,没有问题,接下来对68结点和他的孩子进行排序。
这时候出现一个问题:
如果对68结点进行排序的时候,被换到原本55结点所在的位置,且比此时他的孩子结点的值还要小怎么办?
所以我们只能继续进行排序,在对上一层进行排序的时候,如果被换到下级的子大顶堆的时候,此时就不一定还能继续构成子大顶堆,所以需要对之前的子节点重新进行排序。
进行堆排序
在我们形成大顶堆之后,下一步便是进行堆排序,我们将根节点(被排序后数据最大得结点)与大顶堆当中最后一个结点进行数据交换,之后再对除了刚刚被交换到末尾的结点之外的所有结点进行排序重新形成大顶堆。每次排序大顶堆的时候都忽略掉被交换过去的结点。
实现代码如下:
static void HeapSort(int[] data)
{
for (int i = data.Length / 2; i >= 1; i--)
{
HeapAjust(i, data, data.Length);
}
for (int i = data.Length; i > 1; i--)
{
int temp = data[0];
data[0] = data[i - 1];
data[i - 1] = temp;
HeapAjust(1, data, i - 1);
}
}
private static void HeapAjust(int NodeNum, int[] data, int maxIndex)//传入需要进行堆排序的结点,堆所在的数组,以及堆排序的范围
{
int MaxNodeData = NodeNum;
int var = NodeNum;
while (true)
{
int LeftNodeNumber = var * 2;
int RightNodeNumber = LeftNodeNumber + 1;
if (LeftNodeNumber <= maxIndex && data[LeftNodeNumber - 1] > data[var - 1])
{
MaxNodeData = LeftNodeNumber;
}
if (RightNodeNumber <= maxIndex && data[RightNodeNumber - 1] > data[var - 1] && data[MaxNodeData - 1] < data[RightNodeNumber - 1])
{
MaxNodeData = RightNodeNumber;
}
if (MaxNodeData != var)
{
int temp = data[var - 1];
data[var - 1] = data[MaxNodeData - 1];
data[MaxNodeData - 1] = temp;
var = MaxNodeData;
}
else
{
break;
}
}
}