可以看看大佬的博客,讲解很好,博客
模板
这里同时也是第一种建堆的方式,也就是有一个已知序列然后进行建堆。
//堆排序 升序采用大顶堆,降序采用小顶堆
#include <iostream>
using namespace std;
int a[500001];
void adjust(int v, int n)
{
for (int i=2*v; i<=n; i=i*2)
{
if (i+1 <= n && a[i] < a[i+1]) //修改当前的节点信息后
i++; //可能导致整个树失衡,
//应该继续往下调整,使下面调整过的依然满足大顶堆
if (a[i] > a[v])
{
swap(a[i], a[v]);
v = i;
}
else
{
break;
}
}
}
void slove(int n)
{
for (int i=n/2; i>=1; i--) //从第一个非叶子节点进行调整,
{ //叶子全都不用考虑,因为在调整其父节点时会处理叶子节点
adjust(i, n);
}
for (int i=n; i>1; i--) //每次把a[1]也就是最大的元素放到数组最后,
{ //并把数组顺序减一,因为不能再调整已经交换过的点了
swap(a[i], a[1]);
adjust(1, i-1);
}
}
int main()
{
int n;
cin >> n;
for (int i=1; i<=n; i++)
{
cin >> a[i];
}
slove(n);
for (int i=1; i<=n; i++)
cout << a[i] << " ";
return 0;
}
模板
接下来就是没有已知序列,通过不断地插入元素来扩充堆,两种方式建出来的堆是不一样的,不信的可以试一下,{46 23 26 24 10} 这个集合建小顶堆后结果就是不一样的。对于第一个来说时间复杂度为O(n),这个时间复杂度为O(nlogn)。这里就放直接可运行的代码了,如果想尝试上面的例子,别忘记把上面代码建堆改为建小顶堆。
#include <iostream>
using namespace std;
int a[500001];
void adjust(int v)
{
for (int i=v/2; i>=1; i/=2)
{
if (a[v] < a[i])
{
swap(a[v], a[i]);
v = i;
}
else
{
break;
}
}
}
int main()
{
int n, m;
cin >> n >> m;
for (int i=1; i<=n; i++)
{
cin >> a[i];
for (int j=i; j>=1; j--)
{
adjust(i);
}
}
return 0;
}
第三种
直接调用STL的heap,不过头文件是algorithm。建堆可以直接 make_heap(a, a+n); 堆排序就是sort_heap(a, a+n),我试了一下,堆排序之前的的序列可以不是一个堆,sort_heap会自动调整为堆,默认是建大顶堆的,排序也就是升序。如果你需要的话,可以自己写一个比较函数,不知道的就百度一下吧,我就是在这里简单介绍一下。