一般都用数组来表示堆,
i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。
如第0个结点左右子结点下标分别为1和2。
堆排序方法对记录数较少的文件并不值得提倡,但对n较大的文件还是很有效的。
因为其运行时间主要耗费在建初始堆和调整建新堆时进行的反复“筛选”上。
堆排序在最坏的情况下,其时间复杂度也为O(nlogn)。
相对于快速排序来说,这是堆排序的最大优点。
i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。
如第0个结点左右子结点下标分别为1和2。
堆排序方法对记录数较少的文件并不值得提倡,但对n较大的文件还是很有效的。
因为其运行时间主要耗费在建初始堆和调整建新堆时进行的反复“筛选”上。
堆排序在最坏的情况下,其时间复杂度也为O(nlogn)。
相对于快速排序来说,这是堆排序的最大优点。
此外,堆排序仅需一个记录大小的供交换用的辅助存储空间。
<pre name="code" class="java">
package org.leopard.heap;
public class HeapSort {
public static void main(String[] args) {
int[] a = {1,3,2,45,4,33,40,9,10,22,60,50,22};
new HeapSort().HeapSort(a, a.length);
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
}
void AdjustHeap(int A[], int hLen, int i)
{
int left = 2 * i + 1; //节点i的左孩子
int right = 2 * i + 2; //节点i的右孩子节点
int largest = i;
int temp;
if(i <= hLen/2-1)
{
if (left < hLen && A[largest] < A[left])
{
largest = left;
}
if (right < hLen && A[largest] < A[right])
{
largest = right;
}
if (i != largest) //如果最大值不是父节点
{
temp = A[largest]; //交换父节点和和拥有最大值的子节点交换
A[largest] = A[i];
A[i] = temp;
// i = largest; //新的父节点,以备迭代调堆
// left = 2 * i + 1; //新的子节点
// right = 2 * i + 2;
AdjustHeap(A, hLen, largest);
}
}
}
/*
输入:数组A,堆的大小hLen
功能:建堆
*/
void BuildHeap(int A[], int hLen)
{
int i;
int begin = hLen/2 - 1; //最后一个非叶子节点
for (i = begin; i >= 0; i--)
{
AdjustHeap(A, hLen, i);
}
}
/*
输入:数组A,待排序数组的大小aLen
功能:堆排序
*/
void HeapSort(int A[], int aLen)
{
int hLen = aLen;
int temp;
BuildHeap(A, hLen); //建堆
while (hLen > 1)
{
temp = A[hLen-1]; //交换堆的第一个元素和堆的最后一个元素
A[hLen-1] = A[0];
A[0] = temp;
hLen--; //堆的大小减一
AdjustHeap(A, hLen, 0); //调堆
}
}
}