以从小到大的顺序进行说明。
堆排序
堆排序是指利用堆(大根堆、小根堆)进行排序。
原理:大根堆的根节点的值要比孩子节点的值大,从而就可以每次调整都少调整一个最后一个叶子结点,那么就可以
将最大值源源不断地向后放
。
- 主要用到的还是向下调整算法,不过每次调整的时候会将
调整的范围缩小一个
- 在进行堆排序之前需要进行建大根堆(
每次将大值移到最后才能实现从小到大
)- 建完堆后就可以循环往复地去进行向下调整建堆
时间复杂度
O(n*log2n)
建堆的复杂度是O(n)
向下调整的算法复杂度是O(nlog2n)
最终复杂度是:O(n) + O(nlog2n),可以将O(n)省略
空间复杂度
O(1)
无额外空间消耗
稳定性
不稳定
代码
public void heapSort(int[] array) {
// 先建大根堆
createBigHeap(array);
int end = array.length-1;
while (end > 0) {
// 交换第一个和最后一个
swap(array, 0, end);
siftDown(array,0, end);
end--;
}
}
private void createBigHeap(int[] array) {
// 找到最后一个根节点后向上开始向下调整
for (int parent = (array.length - 1 - 1) / 2; parent >= 0; parent--) {
siftDown(array, parent, array.length);
}
}
/**
* 向下调整,从小到大需要建大根堆
* @param array
* @param parent
*/
private void siftDown(int[] array, int parent, int end){
// 左孩子
int child = 2 * parent + 1;
while (child < end) {
// 如果右孩子存在,并且右孩子的值大于左孩子的值,将child调整为右孩子的下标
if (child + 1 < end && array[child + 1] > array[child]) {
child = 2 * parent + 2;
}
// 进行交换
if (array[parent] < array[child]) {
swap(array, parent, child);
// 向下调整
parent = child;
child = 2 * parent + 1;
} else {
// 已经完成了剩余的建堆
break;
}
}
}
private void swap(int[] array, int i, int j) {
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}