极光 · 哈夫曼树の生成(线段树结构 非指针)(仿邻接表)

ASRC-极光科研中心  哈夫曼编码 - 非指针实现

思想参考AcWing图论中,对于【邻接表】的运用
因为【结构体优先队列】似乎无法对【node*】的排序
暂时无法突破这个技术难点,只能退而求其次
不过调整后的实际运用效果还是不错的

2022-06-22  鸿蒙纪元·乾坤 Day294


这里就是LR改成int,用idx作为指针
优势在于规避了 node *l,*r 的出现,可以实现同样效果
缺点在于需要预定义内存,不能实现动态内存和释放
从我实践的角度出发,算法竞赛中是以实现为目的

不要太追求这种细枝末节
以后的工程实践过程中再考虑这种产品优化的问题吧

详细思想的介绍:算法设计与分析2022 · 云端实验库_影月丶暮风的博客-CSDN博客

结果展示

结点读入后,优先队列内存储的信息

极光 · 哈夫曼树の生成(线段树结构 非指针)(仿邻接表)_第1张图片

极光 · 哈夫曼树の生成(线段树结构 非指针)(仿邻接表)_第2张图片

测试数据

极光 · 哈夫曼树の生成(线段树结构 非指针)(仿邻接表)_第3张图片

极光 · 哈夫曼树の生成(线段树结构 非指针)(仿邻接表)_第4张图片

极光 · 哈夫曼树の生成(线段树结构 非指针)(仿邻接表)_第5张图片

数据部署模块

极光 · 哈夫曼树の生成(线段树结构 非指针)(仿邻接表)_第6张图片

        这里idx是模范邻接表的书写(AcWing),规避了node *l,*r 的书写
采用后者书写将无法使用结构体优先队列(科研部前期研究产物)

极光 · STL库测试 · priority_Queue与Struct_影月丶暮风的博客-CSDN博客

        另外,wlr三数组是共享一个idx下标的;idx总是指向新节点即将存储的位置

        wlr三剑客,是实际结点的存储位置,node结构只在哈弗曼树生成初期参与

        WLR三剑客生成完成后,弃用node和优先队列(呜呜好可怜

我们通过结构体优先队列,生成【node辅助接点】

        codes_idx是看当前生成的path,是哪个【叶子结点】的 【下标idx】

书写优化模块

极光 · 哈夫曼树の生成(线段树结构 非指针)(仿邻接表)_第7张图片

 调试辅助函数

极光 · 哈夫曼树の生成(线段树结构 非指针)(仿邻接表)_第8张图片

主战函数

极光 · 哈夫曼树の生成(线段树结构 非指针)(仿邻接表)_第9张图片

读入模块

极光 · 哈夫曼树の生成(线段树结构 非指针)(仿邻接表)_第10张图片

 建树过程-利用优先队列

极光 · 哈夫曼树の生成(线段树结构 非指针)(仿邻接表)_第11张图片

 我说的【结点虚空层面】就是在优先队列里边的node,因为弹出读取之后就弃用了
实际上我们最后生成的哈夫曼树的结点是存在【WLR三剑客】顺序表中的

        后者被我称作【结点实体层面】

展示哈夫曼编码的俩函数(前者可以调动find函数,将搜索的路径存储为strintg)

极光 · 哈夫曼树の生成(线段树结构 非指针)(仿邻接表)_第12张图片

 哈夫曼路径生成函数

极光 · 哈夫曼树の生成(线段树结构 非指针)(仿邻接表)_第13张图片

// 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 天璇
*/

你可能感兴趣的:(ASRC,·,极光科研中心,霍夫曼树,算法,c++,蓝桥杯,vscode)