堆排序代码模板

 堆排序代码模板_第1张图片

 堆排序代码模板_第2张图片

#include
using namespace std;
const int N = 1e5 + 9;
int h[N], n, m, Size;//小根堆

//u表示三个点中的根节点
void down(int u)
{
	int t = u;//设t为三个点中最小的那个点
	//如果左儿子存在并且小于根节点就将左儿子赋值给t
	if (u * 2 <= Size && h[u * 2] < h[t]) t = u * 2;
	//右儿子
	if (u * 2 + 1 <= Size && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
	//如果传入的节点不是最小值就交换
	if (u != t)
	{
		swap(h[u], h[t]);
		down(t);//将原本的根节点沉下来
	}
}

int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> n >> m;
	//开始创建堆的时候,元素是随机插入的,所以不能从根节点开始down
	//而是要找到满足下面三个性质的结点:
	//1.左右儿子满足堆的性质。
	//2.下标最大(因为要往上遍历)
	//3.不是叶子节点(叶子节点一定不满足堆的性质)
	for (int i = 1; i <= n; ++i) cin >> h[i];
	Size = n;
	//时间复杂度为O(n)
	//在堆中,每个节点的左子节点的下标为2i,右子节点的下标为2i+1
	//假设堆中有n个节点,下标从1到n。我们知道叶子节点是没有子节点的
	//所以最后一个非叶子节点的下标一定小于等于n/2。
	//首先要明确要进行down操作时必须满足左儿子和右儿子已经是个堆
	for (int i = n / 2; i; --i) down(i);
	//应该是不能从头往下down吧,down操作是把小数扔上来
	//大数扔下去,从头往下down把第一个三角里的最小值扔到第一个位置
	//就不再管他了,但是并不能保证其能小于剩下的所有值
	//但从下往上down可以保证建堆时全部点完全从小到大
	//for (int i = 1; i <= n; i++) down(i);//错误
	//for (int i = n; i >= 0; i--) down(i);//正确
	//for (int i = n / 2; i >= 0; i--) down(i);//也正确
	while (m--)
	{
		//本题输出最小值需要删除前面的最小值
		//原本查询最小值只需要h[1],但是现在是前m个数
		//所以需要用到删除第一个数的方法
		cout << h[1] << " ";
		h[1] = h[Size--];
		down(1);//将原本在最后的节点往下沉
	}
	return 0;
}

你可能感兴趣的:(c++,算法)