P3378 【模板】堆

P3378 【模板】堆 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题干详见上述链接, 本文不讨论堆,哈夫曼树的定义,仅提供一个实现思路

这道题是标准的小顶堆,堆有很多实现方式,其中最重要的是对上渗和下渗的理解,借由此题,我写了一个模板,主要用于解决哈夫曼树的建立(没错这道题只是顺手做了罢了,写个结构体,把他的指针塞里面就是一个"森林了"),没有用using指令,可能看着有些怪,其中cmp是排序依据的函数指针(有默认函数),像sort函数一样使用就好了,该类使用时要向vector一样,使用<typename>指定里面存放的元素类型,如果有什么问题,欢迎指出,我会尽快更正

以下是代码:

#include<iostream>
#include<stdio.h>
#include<vector>
#include<exception>


//注释以大顶堆为例
template<typename element>
class Heap
{
public:
	Heap();
	~Heap();
	Heap(bool (*cmp)(element a, element b));//提供一个函数指针来改变排序依据
	void insert(element x);//插入一个元素
	void remove();//删除堆顶元素
	element& query();//返回堆顶元素的引用
	bool empty();//判断是否为空
	long long size();//返回长度
	void showHeap();

private:
	std::vector<element> arr;
	bool (*cmp)(element a, element b);
	void up(int pos);//上渗
	void down(int pos);//下渗
	static bool g_cmp(element a, element b);
};

template<typename element>
Heap<element>::Heap()
{
	//获取类型
	//arr.push_back(0);
	//std::printf("%s\n", typeid(arr[0]).name());
	this->cmp = g_cmp;
}

template<typename element>
Heap<element>::~Heap()
{
}

template<typename element>
Heap<element>::Heap(bool(*cmp)(element a, element b))
{
	this->cmp = cmp;
}

template<typename element>
void Heap<element>::insert(element x)
{
	arr.push_back(x);
	up((int)arr.size() - 1);
}

template<typename element>
void Heap<element>::remove()
{
	arr[0] = arr[arr.size() - 1];
	arr.pop_back();
	down(0);
}

template<typename element>
bool Heap<element>::empty()
{
	return arr.empty();
}

template<typename element>
long long Heap<element>::size()
{
	return arr.size();
}

template<typename element>
void Heap<element>::up(int pos)
{
	if ((pos + 1) / 2 - 1 >= 0 && cmp(arr[pos], arr[(pos + 1) / 2 - 1]))
	{
		//当pos有父亲,并且他比父亲大
		element temp = arr[pos];
		arr[pos] = arr[(pos + 1) / 2 - 1];
		arr[(pos + 1) / 2 - 1] = temp;
		up((pos + 1) / 2 - 1);
	}
}

template<typename element>
void Heap<element>::down(int pos)
{
	int son1 = (pos + 1) * 2 - 1;
	int son2 = (pos + 1) * 2;
	if (son1 >= 0 && son1 < arr.size() && son2 >= 0 && son2 < arr.size())
	{
		//两个孩子均存在
		if (!cmp(arr[pos], arr[son1]) && !cmp(arr[pos], arr[son2]))
		{
			//两个孩子都比父亲大
			if (cmp(arr[son1], arr[son2]))
			{
				//左孩子更大
				element temp = arr[pos];
				arr[pos] = arr[son1];
				arr[son1] = temp;
				down(son1);
			}
			else
			{
				//右孩子更大
				element temp = arr[pos];
				arr[pos] = arr[son2];
				arr[son2] = temp;
				down(son2);
			}
		}
		else if (!cmp(arr[pos], arr[son1]))
		{
			//左孩子比父亲大
			element temp = arr[pos];
			arr[pos] = arr[son1];
			arr[son1] = temp;
			down(son1);
		}
		else if (!cmp(arr[pos], arr[son2]))
		{
			//右孩子比父亲大
			element temp = arr[pos];
			arr[pos] = arr[son2];
			arr[son2] = temp;
			down(son2);
		}
	}
	else if (son1 >= 0 && son1 < arr.size())
	{
		//左孩子存在
		if (!cmp(arr[pos], arr[son1]))
		{
			//左孩子比父亲大
			element temp = arr[pos];
			arr[pos] = arr[son1];
			arr[son1] = temp;
			down(son1);
		}
	}
	else if(son2 >= 0 && son2 < arr.size())
	{
		//右孩子存在
		if (!cmp(arr[pos], arr[son2]))
		{
			//右孩子比父亲大
			element temp = arr[pos];
			arr[pos] = arr[son2];
			arr[son2] = temp;
			down(son2);
		}
	}
}

template<typename element>
bool Heap<element>::g_cmp(element a, element b)
{
	return a > b;
}

template<typename element>
void Heap<element>::showHeap()
{
	for (int i = 0; i < arr.size(); i++)
	{
		std::cout << arr[i]->data << " ";
	}
	std::cout << "\n";
}

template<typename element>
element& Heap<element>::query()
{
	// TODO: 在此处插入 return 语句
	if (arr.empty())
	{
		throw std::overflow_error("禁止查询空堆");
	}
	return arr[0];
}


bool cmp(int a, int b)
{
	return a < b;
}


int main()
{
	int n = 0;
	int op = 0;
	int x = 0;
	Heap<int> heap(cmp);

	std::cin >> n;
	while (n--)
	{
		std::cin >> op;
		switch (op)
		{
			case 1:
				std::cin >> x;
				heap.insert(x);
				break;
			case 2:
				std::cout << heap.query() << "\n";
				break;
			case 3:
				heap.remove();
				break;
			default:
				break;
		}
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值