堆排序
堆是什么呢?是一种特殊的二叉树,就像下面这棵树一样。
有没有发现什么特点,就是所有的父子点都要比子节点要小,(注意圆圈里面的数是值,圆圈上面的数是这个节点的编号),符合这样的特点的完全二叉树,我们称为最小堆,反之,如果所有的父子点都要比子结点要大,这样的完全二叉树,我们称之为最大堆,那么,这一特性究竟有什么用呢?
例如,我们要从14个数里面找出最小值,时间复杂度就是O(N),那如果我们还要把它删除,再加一个新的数,再排序呢?那时间复杂度就是O(N^2),但是如果掌握了对于排序的话,他的时间复杂度就是O(NlogN),时间大大缩减,并且他的时间复杂度确实是跟快排一样的,下面话不多说,请看。
#include<bits/stdc++.h>
using namespace std; //速度与快速排序一样,大于等于O(N),小于等于O(NlogN)
int a[100001]; //小到大,是最小堆,大到小则是最大堆,这个是最小堆,把s函数的小于号换了就是最大堆了
int n;
void s(int i) {
int f=0,t;
while(i*2<=n&&!f) {
if(a[i]<a[i*2]) //记录最大值,最大值要往后面移
t=i*2;
else
t=i;
if(2*i+1<=n) {
if(a[t]<a[2*i+1])
t=2*i+1;
}
if(t!=i) {
swap(a[t],a[i]); //交换
i=t; //记录此时的t,因为还要while
} else
f=1; //终止循环的条件
}
return;
}
int main() {
cin>>n;
int m;
m=n;
for(int i=1; i<=n; i++)
cin>>a[i];
for(int i=n/2; i>=1; i--) //建堆,二叉树,即父子点永远小于等于子结点
s(i);
while(n>1) { //开始排序,此时n的值会改变,函数中n的值也会改变
swap(a[1],a[n]);
n--;
s(1);
}
for(int i=1; i<=m; i++) //因为在函数中n的值会改变,变为1,所以用m,m事先赋值为最开始的n了
printf("%d ",a[i]);
return 0;
}