时间复杂度:O(n*logn) 以2为底的对数
空间复杂度:O(1)
稳定性:不稳定
/// <summary>
/// 堆排序
/// </summary>
/// <param name="nums">待排数据</param>
public void Sort(int[] nums)
{
//基本思路:第1轮 将全部元素调整为大根堆,将根节点和最后一个元素交换
// 第2轮 将除了最后一个元素外的元素调整为大根堆, 将根节点和倒数第二个元素交换
// 。。。。。
//将所有元素调整为大根堆 由于Heapify的使用限制 所以从最后一个非叶子节点开始调整
//n个节点完全二叉树 下标0-n/2-1为非叶子节点
for (int i = nums.Length / 2 - 1; i >= 0; i--)
{
Heapify(nums, i, nums.Length);
}
//需要调换n-1次
for (int i = 0; i < nums.Length - 1; i++)
{
//将根和倒数第x个元素调换
int tmp = nums[0];
nums[0] = nums[nums.Length - i - 1];
nums[nums.Length - i - 1] = tmp;
//将前面的继续调整为大根堆 后面已经有序的除外
Heapify(nums, 0, nums.Length - i - 1);
}
}
/// <summary>
/// 调整大根堆
/// 使用前提:rootIndex的子节点的子树为空或者为大根堆
/// 该方法调整rootIndex根 可能会将子节点中大的和根交换 如果其子节点的子树为空则仍符合大根堆
/// 如果子节点的子树为大根堆 则调整后和根节点互换的子节点的子树不符合大根堆 方法会继续循环调整 另一个子节点仍符合大根堆
/// 但是如果其子节点的子树不是大根堆 该方法只能调整和根节点互换的子节点的子树 另一个无法保证
/// </summary>
/// <param name="nums">待排序列</param>
/// <param name="rootIndex">要调整的根节点下标</param>
/// <param name="length">大根堆中的节点个数</param>
void Heapify(int[] nums, int rootIndex, int length)
{
//下标从0开始 则rootIndex的左孩子 2*rootIndex+1
int lchild;
//判断孩子是否存在 并判断和谁交换(较大的交换)
while ((lchild = 2 * rootIndex + 1) < length)
{
//左右孩子比较 确定较大的孩子
if (lchild + 1 < length && nums[lchild] < nums[lchild + 1])
{
lchild++;//lchild为要和根交换的
}
if (nums[rootIndex] < nums[lchild])
{
//交换
int tmp = nums[lchild];
nums[lchild] = nums[rootIndex];
nums[rootIndex] = tmp;
//将lchild看做根 继续判断 因为以该节点为根的树可能不符合条件
rootIndex = lchild;
}
else
{
//如果符合大根 则退出
break;
}
}
}