堆排序
类似于选择排序,但是相比于选择排序,利用“堆”的性质,提供了一种从未排序部分找到最大元素的有效方法,所需要的比较次数少得多。
Tips:
- 时间复杂度:O(nlogn),最坏情况下仍为O(nlogn),因为“堆”使得速度有保证。
- 空间复杂度:O(1)
- 是一种不稳定排序
- 如果要升序排,那么就要构建最大堆,每次调整完就把堆顶元素与最后一个元素交换,然后最后一个元素不再参与排序,不断缩小无序元素区间;
- “头往上取,判断往下走”:构建一个最大堆时,start元素从最后一个dad节点往前取;再从start元素,往下判断or交换;
// 为了升序排,调整为最大堆
void maxHeapify(vector<int> &A, int start, int end){
int dad = start, son = dad*2 + 1;
while(son <= end){
// 得到左右孩子中更大的那个
if(son+1 <= end && A[son+1] > A[son])
++son;
if(A[dad] > A[son])
break;
else{
swap(A[son], A[dad]);
dad = son; // 从被交换过去的元素开始,再次判断
son = 2*dad + 1; // 从dad元素,逐渐往下走,直到超过end
}
}
}
void heapSort(vector<int> &A){
int len = A.size();
// Edge case:
if(len == 1) return;
// 首先,构建一个最大堆。start元素从最后一个dad节点开始,逐步往上取
for(int start = len/2-1; start >= 0; --start){
maxHeapify(A, start, len-1);
}
// 已经得到了一个最大堆,开始不断地把堆顶元素放到最后,作为已经排完序的元素,不再参与排序
for(int end = len-1; end >= 1; --end){
swap(A[0], A[end]);
maxHeapify(A, 0, end-1); // 最后一个元素,不再参与排序
}
}