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;
}
}
}