目录
一 基本思想1.1 什么是堆1.2 堆排序
二 例子三 时间复杂度
一 基本思想
1.1 什么是堆
堆是具有下列性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆; 或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。堆的根结点一定是堆中的最大(小)者。
1.2 堆排序
将排序的序列构成一个大顶堆。此时,整个序列的最大值就是堆顶的根节点。将它移走(其实就是将其与堆数组的末尾元素交换),然后将剩余的 n - 1 个序列重新构成一个堆, 这样就会得到 n 个元素的次小值。如此反复执行, 便能得到一个有序序列了。
二 例子
public void Sort(int[] array
)
{
int length
= array
.Length
;
for (int i
= (length
- 1) / 2; i
>= 0; i
--)
{
HeapAdjust(array
, i
, length
);
}
for (int i
= length
- 1; i
>= 0; i
--)
{
Swap(array
, 0, i
);
HeapAdjust(array
, 0, i
);
}
}
private void HeapAdjust(int[] array
, int index
, int length
)
{
int temp
= array
[index
];
for (int i
= 2 * index
+ 1; i
< length
; i
= 2 * i
+ 1)
{
if ((i
< length
- 1) && array
[i
] < array
[i
+ 1])
{
i
++;
}
if (temp
>= array
[i
])
{
break;
}
array
[index
] = array
[i
];
index
= i
;
}
array
[index
] = temp
;
}
private void Swap(int[] array
, int i
, int j
)
{
int temp
= array
[i
];
array
[i
] = array
[j
];
array
[j
] = temp
;
}
三 时间复杂度
堆排序的运行时间主要消耗在初始构建堆和重建堆时的反复筛选上。在构建堆的过程中,因为完全二叉树是从最底下最后边的非终端结点开始构建,将它与其孩子进行比较和互换, 对于 每个非终端结点来说, 最多进行两次比较和互换操作, 因此整个构建堆的时间复杂度是 O(n)。重建堆时, 第 i 次 取堆顶数据,并重建堆,的时间复杂度是 O(log₂ i)(因为完全二叉树第 i 个结点到根节点的距离为(log₂ i + 1)),总共需要取 n - 1 次 堆顶数据, 因此 重建的时间复杂度为 O(nlog₂ n)。总体来说, 堆排序的时间复杂度就是 O(nlog₂ n)。由于堆排序对原始数据的排序状态不敏感, 因此, 无论是最好,最差,还是平均情况的时间复杂度都是 O(nlog₂ n)。这在性能上远远好过于冒泡、简单选择、直接插入的时间复杂度O(n²)。由于初始构建堆所需的比较次数较多, 因此。它不适合待排序序列个数较少的情况。