这次想写一下堆排序,之前遇到过好多次有关堆排序的问题,无论是编程还是选择题。但是对这个堆排序一直是稀里糊涂,一个原因网上好多博客写的烂,众说纷纭,各执一词,还有一个原因是自己没有真正想要搞懂一个问题,真正搞透问题。
好了废话不多说开始讲解这次的主角堆排序。
堆排序步骤
堆排序的步骤主要是三个:
- 将序列构建成堆,然后整理这个堆,如果最终需要得到升序->大顶堆,降序->小顶堆
- 将堆顶元素和末尾元素互换,将最大元素放到堆的最后
- 然后调整这个堆,将除了最后一个元素之外的其他元素按照堆的顺序进行整理,然后再将堆顶元素和最后一个元素(除了刚刚已经被放在最后一个的元素)进行互换位置。
这个地方有很多地方都是坑:
一个就是:
首先必须按照最后的排序要求构建大顶堆还是小顶堆!!!
首先必须按照最后的排序要求构建大顶堆还是小顶堆!!!
首先必须按照最后的排序要求构建大顶堆还是小顶堆!!!
第二个就是:
(这个步骤非常重要)构建大顶堆,小顶堆的方法:从最后一个非叶子节点(这个节点的位置非常有意思:如果节点数为奇数:n/2-1; 如果节点数是偶数:n/2)开始调整,将这个节点和自己的两个子节点进行比较,将这三个节点中最大或者最小的放在根节点处,从右向左,从下向上,依次整理过去。
第三个就是:
互换堆顶和末尾节点之后,末尾节点就不考虑了(排除在后续操作之外了)
复杂度
堆排序的平均时间复杂度、最好情况时间复杂度、最差情况时间复杂度都是
O
(
n
l
o
g
2
n
)
O(nlog_2n)
O(nlog2n)
空间复杂度:
O
(
1
)
O(1)
O(1)
堆排序是一种不稳定的排序。
C++实现代码
//调用heap_sort,其中data为待排序的数组,heapsize为数组长度
void heapsort(int data[],int heapsize){
//堆排序算法实现主体:先用build_max_heap将输入数组构造成大顶堆
//将data[0]和堆的最后一个元素交换
//继续进行调整
build_max_heap(data,heapsize);
for(int i=heapsize-1;i>0;i--){
int t=data[0];
data[0]=data[i];
data[i]=t;
max_heapify(data,0,i);
}
}
void build_max_heap(int data[],int heapsize){
//建堆的过程,通过自底向上地调用max_heapify来将一个数组data[1...n]变成一个大顶堆
//只对除了叶子节点之外的节点进行调整
for(int i=heapsize/2-1;i>=0;i--)
max_heapify(data,i,heapsize);
}
void max_heapify(int data[],int i,int heapsize){
//以某个节点为根节点的子树进行调整,调整为大顶堆
int l=2*i+1;
int r=2*i+2;
int largest =i;
if(l<heapsize && data[l]>data[i]){
largest =l;
}
if(r<heapsize && data[r]>data[largest]){
largest =r;
}
if(largest!=r){
int temp=data[largest];
data[largest]=data[i];
data[i]=temp;
max_heapify(data,largest,heapsize);
}
}