数据结构与算法基础(王卓)(21):哈夫曼编码(1):过程

逻辑雏形

根据老师讲解的思路,梳理出程序运行的逻辑雏形如下:

  1. 搞一个多维数组HC,用来存储我们这里 n(每) 个节点的哈夫曼编码
  2. 搞一个数组cd,用来存储我们这里每个节点是前面一位的左子树(0)还是右子树(1),给cd最后一位放结束存储字符
  3. 反复向上回溯:每次都通过找(parent)来判断自己是左子树还是右子树,并且在cd表里记录每次的查询结果,然后再继续向上回溯看上一层(parent),在进行同样(相同)的循环操作
  4. 给HC开辟相应的,每个节点对应需要的存储空间大小的空间
  5. 每算完一个节点的哈夫曼编码就把它放(复制)到HC里面
  6. 释放空间,结束

需要注意的是,由于我们的函数抬头是:

void CreatHuffmanCode(HuffmanTree HT, HuffmanCode& HC, int n)

也就是说我们在一开始的时候,就已经传进来了一颗哈夫曼树,所以我们这里在函数里面不用再重新重复算一遍哈夫曼树


第一步:

创建二维数组HC,同时也要确定(定义)下来【HuffmanCode】的类型是什么

typedef char **HuffmanCode;
//typedef char** HuffmanCode;

void CreatHuffmanCode(HuffmanTree HT, HuffmanCode& HC, int n)
{
    HC = new char *[n + 1];  
}

(1):这里,关于这个定义我们可以这样来理解:

HuffmanCode是一个内部内容为char类型的一个多维数组(这里应该是二维数组)

*(*HuffmanCode):表示二维数组的子集:

表示若干个一维数组,每个数组都是一个char类型的一个一维数组

**HuffmanCode:一个二维数组

由若干个char类型一维数组组成的一个二维数组

其中每一个一维数组又可以分为若干个char类型的元素/结点

另外,这里关于开辟空间new的格式使用规则,感觉还是有点不稳的可以直接看:

数据结构与算法基础(王卓)(8)附:关于new的使用方法详解_数据结构中的new_宇 -Yu的博客-CSDN博客


(2):为什么我们给他分配(n+1)个元素(格子)???

猜测:

可能是因为(第)一个用来放表头(头结点),然后后面还有(n)个节点


第二步:

给数组cd开辟空间,标准答案:

    char* cd = new char[n];  //分配存放临时存放编码的动态数组空间
    cd[n - 1] = '\0';

可是我觉得不对吧,为什么在数组倒数第二个位置上放空字符啊?

根据前面实际(操作)的案例,空字符不应该是放在最后一位吗??

🤷 


第三步:

生成哈夫曼编码

我写的:(第一版)

    for (int i = 1; i <= n; i++)
    {    
        int a = HT[i].parent;
        while (HT[a].parent != 0)
        {
            //往cd的最后面一位输入:左0右1
            if (HT[a].lchild == i)
            {
                for (int j = n; n >= 1; n--)//最后面一位空着的字符
                {
                    if (cd[n] != NULL)
                    {
                        cd[n - 1] = 0;
                        break;
                    }
                }
            }
            else
            {
                for (int j = n; n >= 1; n--)
                {
                    if (cd[n] != NULL)
                    {
                        cd[n - 1] = 1;
                        break;
                    }
                }
            }
        }

问题:如果像我这样写,最终会导致:

最后每次的输入都只输入了最后一位的数值,而且还把数组写满了

我写的程序里面的记录HT[i].parent的a,我一直没有对他进行任何操作

他没有任何变化,程序一直在重复写入第一位parent所对应的哈夫曼编码


标准答案:(这里把后面几步也写进去了)

    //逐字符求Huffman编码
    for (int i = 1; i <= n; i++)
    {
        int start = n - 1;
        //表示(记录)我们在cd表当中输入的每个分支(边)其对应的位置序号
        int c = i;
        int f = HT[i].parent;
        while (f != 0)
        {
            start--;
            //每回溯一次,start(写入cd表的信息位置)向前指一个位置
            if (HT[f].lchild == c)//左0右1
                cd[start] = '0';
            else  //是右孩子
                cd[start] = '1';
            //继续向上回溯
            c = f;
            f = HT[f].parent;
        }
        HC[i] = new char[n - start];  //为第i个字符串编码分配空间
        strcpy(HC[i], &cd[start]);  //将求得的编码复制
    }

两种做法思路不同:

我的思路:

  1. 每次都从cd表最后一位往前逐个查找,直至找到第一个空着的位置
  2. 往里面输入数据
  3. 输入完以后直接跳出查找,直接进入下一轮for(i)的循环

标准答案:

  1. 先设立一个变量s,表示(记录)每次cd表当中输入的分支(边)其对应的位置序号
  2. 每输入cd表1次,s就向前指一个位置
  3. 输入
  4. 把比较使用的结点改成parent的结点,然后进入下一轮的循环和比较

优于我的方法的地方:

  • 每次输入cd表时:
  • 设置变量a表示当前输入对应结点的位置
  • 设置变量b表示当前输入对应结点的parent的位置

但是(然而)这里对于标准答案,我也有一个

问题:

他你这个cd表,前面你在输入空字符的时候放在(n-1)的位置,怎么你第一次输入的时候还是放在(n-1)位?


根据标准答案修改以后的个人最终版本:

    for (int i = 1; i <= n; i++)
    {    
        int np = n;//now point
        int pp = HT[i].parent;//parent point
        int insert = n - 1;//inser:插入

        while (HT[pp].parent != 0)
        {
            //每输入cd表1次,下次输入就向前指一个位置
            insert--;

            //往cd的最后面一位输入:左0右1
            if (HT[pp].lchild == i)
                cd[n - 1] = 0;
            else
                cd[n - 1] = 1;

            //把比较使用的结点改成parent的结点,然后进入下一轮的循环和比较
            np = pp;
            pp = HT[np].parent;
        }

第四步:(这里我们就把最后收尾工作合并一起写了)

  1. 给HC开辟相应的,每个节点对应需要的存储空间大小的空间
  2. 每算完一个节点的哈夫曼编码就把它放(复制)到HC里面
  3. 释放空间,结束
        HC[i] = new char[n - insert];
        //copy H[i] from cd to HC;

这里,我们可以按标准答案:

使用 strcpy函数(虽然实际上我也没听说过),最终再用delete释放空间

当然这个过程中还是碰到了一些

问题:

 在前面定义的过程中:

    char* cd = new char[n];

我们可以看到:

cd是一个指向一维数组char[n]的一个指针

也可以是一个二维数组,由若干个一维数组char【n】作为基本单位所构成

而我们要复制拷贝的,是其中某一列(第 i 列)

所以我们写的语句,不应该是这样的吗?:

        strcpy(HC[i], &cd[i]);  //将求得的编码复制

为什么标准答案写的是

        strcpy(HC[i], &cd[start]);  //相当于我们函数里写的:
        //strcpy(HC[i], &cd[insert]); 

???


最终结果见下一节

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/7558.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spark 基本知识介绍

文章目录1. Spark是什么2. Spark与Hadoop区别3. Spark四大特点3.1 速度快3.2 易于使用3.3 通用性强3.4 运行方式4. Spark整体框架5. Spark运行模式6. Spark架构角色6.1 YARN角色6.2 Spark 角色1. Spark是什么 Spark是用于大规模数据处理的统一分析引擎。 Spark 最早源于一篇论…

Qt5.15.2 for WebAssembly 环境搭建 - Windows篇

Qt系列文章目录 文章目录Qt系列文章目录前言一、准备工作二、操作步骤1.使用cmd工具2.安装Qt for WebAssembly3.创建工程WebAssembly3.创建Qt Assembly工程参考前言 由于前端Canvas绘制图像效率问题&#xff0c;而且实现三维特效也有性能瓶颈&#xff0c;虽然Web 技术突飞猛进…

基于Arm Cortex-M4核心MK60DN256VMD10、MK60DX256VMD10嵌入式微控制器芯片介绍

MK60DN256VMD10&#xff08;MK60DX256VMD10&#xff09;是Kinetis K6x系列32位微控制器&#xff0c;基于ArmCortex-M4核心&#xff0c;是与Kinetis Kx MCU家族兼容的引脚&#xff0c;外设和软件。K6x mcu还集成了10/100Mbps以太网与IEEE1588精确时间协议(PTP)收发器和USB 2.0 (…

【Linux-计算机网络】-TCP协议通信流程

1.TCP协议通信流程图 1.1TCP协议的通讯流程可以分为以下步骤&#xff1a; 应用层&#xff1a;应用程序通过系统调用API&#xff08;如socket&#xff09;创建一个TCP套接字&#xff08;socket&#xff09;&#xff0c;并设置好相关的选项。 传输层&#xff1a;当应用程序调用c…

再学C语言49:C库中的字符串函数

C库提供了很多处理字符串的函数&#xff1b;ANSI C用头文件 string.h 给出这些函数的原型 一、strlen()函数 功能&#xff1a;计算并返回字符串长度 示例代码&#xff1a; /* test strlen() function */ #include <stdio.h> #include <string.h>int main(void)…

数据的存储--->【大小端字节序】(Big Endian)(Little Endian)

⛩️博主主页&#xff1a;威化小餅干&#x1f4dd;系列专栏&#xff1a;【C语言】藏宝图&#x1f38f; ✨绳锯⽊断&#xff0c;⽔滴⽯穿&#xff01;一个编程爱好者的学习记录!✨前言计算机硬件有两种存储数据的方式&#xff1a;大端字节序——Big Endian小端字节序——Little …

【Python】【进阶篇】十、Python爬虫的Requests库

目录十、Python爬虫的Requests库10.1 常用请求方法10.1.1 requests.get()10.1.2 requests.post()10.2 对象属性10.3 Requests库应用十、Python爬虫的Requests库 Python 提供了多个用来编写爬虫程序的库&#xff0c;除了前面已经介绍的 urllib 库之外&#xff0c;还有一个很重的…

vue尚品汇商城项目-day07【44.个人中心二级路由搭建+45.我的订单+46.优化登录跳转+47.独享守卫】

文章目录44.个人中心二级路由搭建45.我的订单46.优化登录跳转47.独享守卫本人其他相关文章链接44.个人中心二级路由搭建 修改代码&#xff1a; 将Center拆分为2个组件MyOrderGroupOrder src/router/routes.js import Center from /pages/Center import GroupOrder from /pages…

QT 常见控件使用

1. QLineEdit 添加控件后&#xff0c;可以编辑控件的名称&#xff0c;然后使用名称获取和设置值 QString qstrValue ui->strName->text(); QMessageBox::information(this, "提示", qstrValue); 2.窗体导航切换 添加新的对话框&#xff0c;然后引入头文件…

游戏安全漏洞一些分享

安全界对漏洞的定义为&#xff1a;在硬件、软件、系统等具体实现或者系统安全策略上存在的缺陷&#xff0c;从而使攻击者能够达到于某种破坏效果。游戏安全漏洞属于常规漏洞的子类&#xff0c;常规漏洞的分类如下图所示&#xff1a; 通过以上的漏洞分类图可知游戏漏洞属于常规…

MATLAB | 如何绘制github同款日历热力图

应粉丝要求&#xff0c;出一个类似于github热图的日历热力图&#xff0c;大概长这样&#xff1a; 依旧工具函数放在文末&#xff0c;如有bug请反馈并去gitee下载更新版。 使用教程 使用方式有以下几种会慢慢讲到&#xff1a; heatmapDT(Year,T,V)heatmapDT(Year,T,V,MonLim)h…

被称为“眼黄金”的叶黄素究竟是什么?叶黄素则能过滤蓝光

人眼视觉依赖于黄斑的中心凹陷。黄斑中含有大量的叶黄素&#xff0c;因此被称为“黄斑”。叶黄素&#xff0c;也被称为“眼黄金”&#xff0c;是人类视网膜中最重要的营养物质。它含有黄斑&#xff08;视觉中心&#xff09;和晶状体&#xff0c;特别是黄斑中含有高浓度的叶黄素…

外部中断实验

基础知识及实验目标 目标&#xff1a;通过中断来实现按键对小灯的控制。 WK_UP 翻转小灯&#xff1b; KEY 1控制 DS1按一次亮&#xff0c;再按一次灭&#xff1b;KEY 0控制DS0&#xff0c;按一次亮&#xff0c;再按一次灭。 触发中断的意思就是&#xff1a;当这个IO口达到触发…

MathType公式使用技巧汇总——Mathtype怎么在word中编辑公式?论文中公式有哪技巧?有哪些注意事项?论文中的公式怎么写?

文章目录1 Mathtype安装2 word 段落间插入公式3 文字间嵌入&#xff08;内联&#xff09;公式4 公式修改5 不要使用键盘上的括号等符号5.1 键盘上符号引发的问题5.2 正确的符号使用方法6 常用设置6. 1公式字体大小设置6.2 公式样式设置7 公式标号设置8 MathType怎么设置下一章公…

ESP-C3入门18. 低功耗蓝牙SPP Server端功能测试

ESP-C3入门18. 低功耗蓝牙SPP Server端功能测试一、功能简介1. GATT2. SPP3. SPP Server和 SPP Client二、 SPP Server开发步骤1. 启动 GATT Server2. SPP 任务初始化3. 注册 SPP应用程序4. UART 初始化5. UART 事件处理程序二、完整程序1. 代码和注释2. 运行方法一、功能简介 …

【SQL 必知必会】- 第八课 使用函数处理数据

目录 函数 函数带来的问题 可移植&#xff08;portable&#xff09; 是否应该使用函数&#xff1f; 使用函数 文本处理函数 SOUNDEX 支持 日期和时间处理函数 数值处理函数 函数 函数带来的问题 与几乎所有DBMS 都等同地支持SQL 语句&#xff08;如SELECT&#xff09;不同&am…

Selenium Web UI 自动化分布式运行:SeleniumGrid

简介&#xff1a;Selenium Grid是selenium的三大组件之一&#xff0c;它允许Selenium-RC针对规模庞大的测试案例集或者需要在不同环境中运行的测试案例集进行扩展。通过将客户端命令发送到远程浏览器的实例, Selenium Grid 允许在远程计算机 (虚拟或真实) 上执行WebDriver脚本.…

2016蓝桥杯C/C++B组

剪邮票 解题思路&#xff1a;做法很多&#xff0c;dx[], dy[]做出来不对&#xff0c;4*4 会出现16个方向重复了&#xff0c;只有四个方向要注意。 然后又看到网上的另一个做法使用全排列&#xff0c;用{1, 1 ,1,1,1 ,0&#xff0c;0&#xff0c;0&#xff0c;0}五个1&#xf…

Web漏洞-RCE代码及命令执行漏洞全解-web漏洞产生的原理及条件-墨者靶场详解

目录 一、导图 二、RCE漏洞简介 三、代码执行漏洞示例 四、命令执行漏洞示例 五、漏洞的产生条件 <网站原码层面> <网站应用层面> 六、漏洞检测 七、黑盒-应用层面-漏洞实例 八、白盒-代码层面-漏洞实例 九、黑盒-RCE公开漏洞-漏洞实例 十、漏洞产生的…

推箱子小游戏

文章目录一、 介绍二、 制作墙壁、地面三、 制作箱子四、 制作终点五、 制作人物移动六、 推箱子关键触发机制七、 终点设置八、 关卡切换设置九、 协程十、 下载一、 介绍 2D推箱子游戏是一种益智类游戏&#xff0c;玩家需要控制角色将箱子推到指定的位置&#xff0c;以完成关…