思想参考AcWing图论中,对于【邻接表】的运用
因为【结构体优先队列】似乎无法对【node*】的排序
暂时无法突破这个技术难点,只能退而求其次
不过调整后的实际运用效果还是不错的
2022-06-22 鸿蒙纪元·乾坤 Day294
这里就是LR改成int,用idx作为指针
优势在于规避了 node *l,*r 的出现,可以实现同样效果
缺点在于需要预定义内存,不能实现动态内存和释放
从我实践的角度出发,算法竞赛中是以实现为目的
不要太追求这种细枝末节
以后的工程实践过程中再考虑这种产品优化的问题吧
详细思想的介绍:算法设计与分析2022 · 云端实验库_影月丶暮风的博客-CSDN博客
结点读入后,优先队列内存储的信息
这里idx是模范邻接表的书写(AcWing),规避了node *l,*r 的书写
采用后者书写将无法使用结构体优先队列(科研部前期研究产物)
极光 · STL库测试 · priority_Queue与Struct_影月丶暮风的博客-CSDN博客
另外,wlr三数组是共享一个idx下标的;idx总是指向新节点即将存储的位置
wlr三剑客,是实际结点的存储位置,node结构只在哈弗曼树生成初期参与
WLR三剑客生成完成后,弃用node和优先队列(呜呜好可怜)
我们通过结构体优先队列,生成【node辅助接点】
codes_idx是看当前生成的path,是哪个【叶子结点】的 【下标idx】
我说的【结点虚空层面】就是在优先队列里边的node,因为弹出读取之后就弃用了
实际上我们最后生成的哈夫曼树的结点是存在【WLR三剑客】顺序表中的
后者被我称作【结点实体层面】
// ASRC-极光科研中心 哈夫曼编码 - 非指针实现
// 思想参考AcWing图论中,对于【邻接表】的运用
// 因为【结构体优先队列】似乎无法对【node*】的排序
// 暂时无法突破这个技术难点,只能退而求其次
// 不过调整后的实际运用效果还是不错的
// 2022-06-22 鸿蒙纪元·乾坤 Day294
// 这里就是LR改成int,用idx作为指针
// 优势在于规避了 node *l,*r 的出现,可以实现同样效果
// 缺点在于需要预定义内存,不能实现动态内存和释放
// 从我实践的角度出发,算法竞赛中是以实现为目的,不要太追求这种细枝末节
// 以后的工程实践过程中再考虑这种产品优化的问题吧
#include
#include
#include
#include
#include
using namespace std;
#define top hfm.top()
#define pop hfm.pop()
#define size hfm.size()
#define push(x) hfm.push(x)
//【数据存储模块】
const int N = 1e5 + 7, T = 2 * N - 1;
struct node
{
int w; //权重
int idx; //结点name下标,=0时候表示是生成结点
int st; //实体idx,记录【结点】在【线段表】位置
//【线段表】:wlr三剑客
};
bool operator<(node t1, node t2)
{
return t1.w > t2.w; //新插入T2更小,意图构造大头
//实际上恰好相反
}
int n; //【初始结点个数】
int idx = 1; //【新结点存储位置】仿造邻接表
int HFM; //【哈夫曼树根节点idx】
bool path[N]; //【搜索路径】
string codes[N]; //【结点对应的哈夫曼编码】
int codes_idx; //【哈夫曼编码追踪标记】:当前捕获的path对应哪个结点
int l[T], r[T], w[T]; //【左节点idx】【右节点idx】【结点权值】
priority_queue hfm; //【生成树辅助优先队列】,存储结点对应的idx下标和权值,权值小的往前排
char name[N][27] = {"ASRC-极光科研中心"}; //【结点名称】,
//【测试函数模块】
void show_queue()
{
puts("\n\nASRC 队列内容展示\n");
int tmp = 0;
while (size)
{
printf("%d:权值:%d", ++tmp, top.w);
printf("\t名称:%s\n", name[top.idx]), pop;
}
puts("\n\n");
}
void show_node()
{
puts("\n\n生成的实体层面 【权值展示】");
for (int i = 1; i <= HFM; i++)
printf("%d ", w[i]);
puts("\n\n生成的实体层面 【L展示】");
for (int i = 1; i <= HFM; i++)
printf("%d ", l[i]);
puts("\n\n生成的实体层面 【R展示】");
for (int i = 1; i <= HFM; i++)
printf("%d ", r[i]);
puts("\n\n");
}
//【功能函数模块】
void get_in()
{
scanf("%d", &n);
for (idx = 1; idx <= n; idx++)
{ //跳出的时候,idx指向n+1
scanf("%d%s", &w[idx], &name[idx]);
node tmp = {w[idx], idx, idx};
//第一个idx,结点名称位置,也代表是不是合成结点
//第二个idx,作为一个结点,在实体层面的下标(w中的下标)
push(tmp);
}
}
void c_Tree()
{
while (size != 1)
{
node t1, t2, t3;
t1 = top, pop;
t2 = top, pop;
{ //新建结点(实体层面)
t3.w = w[idx] = t1.w + t2.w;
t3.idx = 0; //表示是【合成结点】
t3.st = idx; //实体层面坐标
l[idx] = t1.st;
r[idx] = t2.st;
}
push(t3); //新建结点(虚空层面)
idx++;
}
HFM = top.st;
}
void find(int way, int step) // destination
{
if (way <= n) //追踪坐标落到了1~n,说明是叶子结点了
{
if (strcmp(name[codes_idx], name[way]) == 0)
{
printf("找到了啊啊啊woc! %s Path=", name[codes_idx]);
for (int i = 0; i < step; i++)
{
printf("%d", path[i] ? 1 : 0);
codes[codes_idx] += path[i] ? '1' : '0';
}
puts("");
}
return;
}
path[step] = false, find(l[way], step + 1);
path[step] = true, find(r[way], step + 1);
}
void show_code()
{
for (int i = 1; i <= n; i++)
codes_idx = i, find(HFM, 0); // 0表示已经走了几步
}
void show_remember()
{
puts("");
for (int i = 1; i <= n; i++)
printf("%d:%s Codes:%s\n", i, name[i], codes[i].c_str());
}
//【主战函数模块】
int main()
{
get_in(); //【结点读入】《读入后,第一次展示》
c_Tree(); //【建立哈弗曼树】wlr三剑客,线段表建树
show_queue(); //【展示优先队列】
show_node(); //【调试-wlr三剑客 内容展示】
show_code(); //【展示,各个结点对应的哈弗曼编码】
show_remember(); //【展示,string生成的哈夫曼编码】
return 0;
// show_queue();//【调试-优先队列 内容展示】破坏性读取(全部弹出)
}
/*
7
12 天枢 46 天权 13 开阳
52 破军 34 玉衡 28 天玑
35 天璇
*/