堆排序
堆排序是一种选择排序。是不稳定的排序方法。时间复杂度为O(nlog2n)。
堆排序的特点是:在排序过程中,将排序数组看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲节点和孩子节点之间的内在关系,在当前无序区中选择关键字最大(或最小)的记录。
基本思想
1.将要排序的数组创建为一个大根堆。大根堆的堆顶元素就是这个堆中最大的元素。
2.将大根堆的堆顶元素和无序区最后一个元素交换,并将无序区最后一个位置例入有序区,然后将新的无序区调整为大根堆。
重复操作,无序区在递减,有序区在递增。
初始时,整个数组为无序区,第一次交换后无序区减一,有序区增一。
每一次交换,都是大根堆的堆顶元素插入有序区,所以有序区保持是有序的。
大根堆和小根堆
堆:是一颗完全二叉树。
大根堆:所有节点的子节点比其自身小的堆
小根堆:所有节点的子节点比其自身大的堆
完全二叉树的基本性质
数组中有n个元素,i是节点
1 <= i <= n/2 就是说数组的后一半元素都是叶子节点。
i的父节点位置:i/2
i左子节点位置:i*2
i右子节点位置:i*2 + 1
如一个数组
物理结构:15 20 35 25 30 40 50
逻辑结构:
15
/
20 35
/ /
25 30 40 50
这是一个小根堆,所有节点的子节点比其自身大。15,20,35是节点,其它的都是叶子。
由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。
例子
using System;
using System.Collections;
namespace System
{
public class Test
{
public static void Main()
{
int[] array = new int[6] { 40, 10, 20, 15, 35, 20 };
HeapSort.Sort(array);
PrintArray(array);
Console.ReadKey();
}
public static void PrintArray(int[] array)
{
for (int i = 0; i < array.Length; i++)
{
if (i > 0) Console.Write(" ");
Console.Write(array[i].ToString());
}
Console.WriteLine();
}
}
public class HeapSort
{
public static void Sort(int[] sortArray)
{
BuildMaxHeap(sortArray);
for (int i = (sortArray.Length - 1); i > 0; i--)
{
Swap(ref sortArray[0], ref sortArray[i]); // 将堆顶元素和无序区的最后一个元素交换
MaxHeapify(sortArray, 0, i); // 将新的无序区调整为堆,无序区在变小
}
}
/// <summary>
/// 初始大根堆,自底向上地建堆
/// 完全二叉树的基本性质,最底层节点是 n/2,所以从 sortArray.Length / 2 开始
/// </summary>
private static void BuildMaxHeap(int[] sortArray)
{
for (int i = (sortArray.Length / 2) - 1; i >= 0; i--)
{
MaxHeapify(sortArray, i, sortArray.Length);
}
}
/// <summary>
/// 将指定的节点调整为堆
/// </summary>
/// <param name="i">需要调整的节点</param>
/// <param name="heapSize">堆的大小,也指数组中无序区的长度</param>
private static void MaxHeapify(int[] sortArray, int i, int heapSize)
{
int left = 2 * i + 1; // 左子节点
int right = 2 * i + 2; // 右子节点
int larger = i; // 临时变量,存放大的节点值
// 比较左子节点
if (left < heapSize && sortArray[left] > sortArray[larger])
{
larger = left;
}
// 比较右子节点
if (right < heapSize && sortArray[right] > sortArray[larger])
{
larger = right;
}
// 如有子节点大于自身就交换,使大的元素上移。
if (i != larger)
{
Swap(ref sortArray[i], ref sortArray[larger]);
MaxHeapify(sortArray, larger, heapSize);
}
}
private static void Swap(ref int a, ref int b)
{
int t;
t = a;
a = b;
b = t;
}
}
}