堆排序
数据结构中的二叉堆能够很好地实现优先队列的基本操作。在二叉堆的数组中,每个元素都大于或等于另两个位置的元素。相反的,或者都小于或等于另两个位置的元素。
堆的实现
将一个普通数组替换成一个二叉堆,首先需要进行建堆操作,比如将3,4,8,7,6替换成8,7,6,3,4类似的结构。
建堆代码如下:
private static void buildHeap(ref int[] a)
{
int length = a.Length - 1;
for (int i = (length - 1) / 2; i >= 0; i--)
{
adjustHeap(ref a, i, length);
}
}
//调整堆的顺序
public static void adjustHeap(ref int[] a, int rootIndex, int lastIndex)
{
int bigerIndex = rootIndex;
int leftIndex = 2 * rootIndex;
int rightIndex = 2 * rootIndex + 1;
if (rightIndex <= lastIndex)//存在右节点
{
if (a[rightIndex] >= a[rootIndex] || a[leftIndex] > a[rootIndex])//存在比根节点大的值
{
bigerIndex = a[rightIndex] > a[leftIndex] ? rightIndex : leftIndex;//判断左右节点,哪个节点值最大
}
}
else if (leftIndex <= lastIndex)//只存在左节点
{
bigerIndex = a[leftIndex] > a[rootIndex] ? leftIndex : rootIndex;
}
if (bigerIndex != rootIndex)
{
execArray(ref a, bigerIndex, rootIndex);
adjustHeap(ref a, bigerIndex, lastIndex);
}
}
rootIndex为根节点所在的位置,lastIndex为数组的长度,调整堆的顺序基本思路为:
if 存在右节点
if 右节点的值大于根节点的值 或 左节点的值大于根节点的值
最大节点的位置等于左右节点最大值所在的位置
else if 如果只存在左节点
if 左节点的值大于根节点的值
最大节点的位置等于左节点的位置
if 最大根节点所在的位置发生了变化
替换根节点和最大节点所在的位置
循环执行判断
当根节点被删除,替换成一个新值时,需要将节点值进行下沉操作。
循环判断节点下子节点所在的值是否比根节点大,进行替换操作。
public static void Sink(ref int[] a, int k)
{
while (2 * k <= a.Length - 1)
{
int j = 2 * k;
if (j < a.Length - 1 && a[j] <= a[j + 1]) j++;
if (a[k] >= a[j]) break;
execArray(ref a,k, j);
k = j;
}
}
如果扩展数组长度,插入一个新元素,那么需要进行上浮操作。
public static void Swim(ref int[] a, int k)
{
while (k > 1 && a[k / 2] < a[k])
{
execArray(ref a, k / 2, k);
k = k / 2;
}
}