当前位置: 首页 > news >正文

数据结构与算法基础-学习-18-哈夫曼编码

一、个人理解

在远程通讯中,需要把字符转成二进制的字符串进行传输,例如我们需要传输ABCD,我们可以用定长的字符串进行表示,例如:

  1. A:00

  1. B:01

  1. C:02

  1. D:03

这样可能就造成空间的浪费,我们多存储了一个0号位。那用变长呢,会怎么样,我们试试,例如:

  1. A:0

  1. B:00

  1. C:01

  1. D:1

如果接收到的二进制字符串为:0000101,在解码时是否就会出现歧义,可以是AAAADAD,也可以是ABCC,也可以是BBDC等等。

从而引入了哈夫曼编码,也称为最优前缀码。之前我们已经实现了哈夫曼树,可以参考文章链接《数据结构与算法基础-学习-17-二叉树之哈夫曼树》,从哈夫曼树这个中间结果,转换出我们想要的哈夫曼编码。

二、为什么哈夫曼编码得出二进制字符串最短呢?

  1. 在生成哈夫曼树之前,我们需要统计字符在数据中出现的概率,出现的概率越高,编码会越短。

  1. 之前介绍过的哈夫曼树的特点,权值越大的结点离根结点越近,也就是路径越短。

  1. 哈夫曼树规定走左子树就标记为0,走右子树就标记为1,从根结点到各个叶子节点的标记拼接起来,就是这个字符的哈夫曼编码。

三、结构体定义

typedef char** HaffmanCode;

四、函数实现

1、生成哈夫曼编码

(1)定义
Status CreateHaffmanCode(HaffmanTree HT, HaffmanCode* HC, HaffmanTreeLentype ArrayLen)
{JudgeAllNullPointer(HT);//Init HaffmanCode*HC          = (HaffmanCode)MyMalloc(sizeof(char*) * ArrayLen);char* TmpHC = (char*)MyMalloc(sizeof(char) * (ArrayLen - 1));//临时数组存放哈夫曼编码中间结果,长度n,编码最长需要n-1,所以分配n-1。HaffmanTreeLentype TmpHCLen = 0;HaffmanTreeLentype i,j;HaffmanTreeLentype TmpParentIndex;//上一个结点的父亲索引。HaffmanTreeLentype TmpIndex;//上一个结点的索引号。for(i = 1; i <= ArrayLen; i++){TmpParentIndex = HT[i].ParentIndex;TmpIndex       = i;while(HT[TmpParentIndex].ParentIndex != 0){if(HT[TmpParentIndex].LeftChildIndex == TmpIndex){TmpHC[TmpHCLen] = '0';TmpHCLen++;}else if (HT[TmpParentIndex].RightChildIndex == TmpIndex){TmpHC[TmpHCLen] = '1';TmpHCLen++;}else{Log("Internal Error : Perant LeftChildIndex and RightChildIndex != TmpIndex",Error);}TmpIndex       = TmpParentIndex;TmpParentIndex = HT[TmpParentIndex].ParentIndex;}//根节点判断if(HT[TmpParentIndex].LeftChildIndex == TmpIndex){TmpHC[TmpHCLen] = '0';TmpHCLen++;}else if(HT[TmpParentIndex].RightChildIndex == TmpIndex){TmpHC[TmpHCLen] = '1';TmpHCLen++;}else{Log("Internal Error : Root Node Perant LeftChildIndex and RightChildIndex != TmpIndex",Error);}//将TmpHC中的字符倒序写入HC中。(*HC)[i-1] = (char*)MyMalloc(sizeof(char) * (TmpHCLen + 1));//编码最长需要n,加上\0,所以分配n+1。for(j = TmpHCLen - 1; j >= 0; j--){(*HC)[i-1][TmpHCLen - 1 - j] = TmpHC[j];if(j == 0)//因为j是无符号长整型,j不能等于负数,当j=-1,退出循环,导致程序core掉,由此添加此判断,避免问题的发生。{break;}}(*HC)[i-1][TmpHCLen] = '\0';TmpHCLen             = 0;}free(TmpHC);TmpHC = NULL;Log("Create HaffmanCode     : OK\n",Info);return SuccessFlag;
}

(2)参数

参数名

说明

HT

传入参数类型为HaffmanTree 的哈夫曼树。

HC

传入参数类型为HaffmanCode*的哈夫曼编码数组指针。

ArrayLen

传入参数类型为HaffmanTreeLentype的权值数组长度。

(3)实现思路

A,B,C,D,E对应的权值如下:

HaffmanTreeLentype WeightArray[]  = {2,4,2,3,3};

生成哈夫曼树如下:

2023-3--[Info]--HaffmanTree            :
[ Index | Weight | ParentIndex | LeftChildIndex | RightChildIndex ]
[ 0     | 0      | 0           | 0              | 0               ]
[ 1     | 2      | 6           | 0              | 0               ]
[ 2     | 4      | 8           | 0              | 0               ]
[ 3     | 2      | 6           | 0              | 0               ]
[ 4     | 3      | 7           | 0              | 0               ]
[ 5     | 3      | 7           | 0              | 0               ]
[ 6     | 4      | 8           | 1              | 3               ]
[ 7     | 6      | 9           | 4              | 5               ]
[ 8     | 8      | 9           | 6              | 2               ]
[ 9     | 14     | 0           | 7              | 8               ]

图示如下:

从根节点开始遍历到每个叶子结点算出哈夫曼编码比较困难,我们反其道而行之,从叶子结点开始遍历到根节点,但我们算出的结果是一个倒序的,我们需要一个临时数组来存储倒序编码,最后再正序填写回哈夫曼编码数组中即可。

例如我们来算一个A,父亲是权值4,走左子树为0,0写入临时数组,

char TmpHC[] = {'0'}; 

再往上走,父亲是权值8,走左子树为0,0写入临时数组,

char TmpHC[] = {'0','0'}; 

再往上走,父亲是权值14,走右子树为1,1写入临时数组,

char TmpHC[] = {'0','0','1'}; 

倒序写回哈夫曼编码数组就是100。其他的大家自己可以算一下,是不是这样,至于和老师讲的可能有不一样的地方,例如最后形成的编码,只是由于数组中选出两个最小的值,哪个是左子树索引,哪个是右子树索引,不一样导致,但不影响编码。最终得出的哈夫曼编码如下:

2023-3--[Info]--HaffmanCode            :
[ Index | Code    ]
[ 1     | 100     ]
[ 2     | 11      ]
[ 3     | 101     ]
[ 4     | 00      ]
[ 5     | 01      ]

2、销毁哈夫曼编码

(1)定义
Status DestoryHaffmanCode(HaffmanCode HC,HaffmanTreeLentype ArrayLen)
{JudgeAllNullPointer(HC);HaffmanTreeLentype i;for(i = 0; i < ArrayLen; i++){free(HC[i]);HC[i] = NULL;}free(HC);HC = NULL;Log("Destory HaffmanCode    : OK\n",Info);return SuccessFlag;
}

(2)参数

参数名

说明

HC

传入参数类型为HaffmanCode*的哈夫曼编码数组指针。

ArrayLen

传入参数类型为HaffmanTreeLentype的权值数组长度。

四、虚机测试

[gbase@czg2 Tree]$ make
gcc -Wall -g ../Log/Log.c BinaryTree.c HaffmanTree.c main.c -o TestBinaryTree -I ../Log/
[gbase@czg2 Tree]$ ./TestBinaryTree 
2023-3--[Info]--Init Global Array      : OK
2023-3--[Info]--Init Binary Tree       : OK
2023-3--[Info]--New Binary Search Tree : OK
2023-3--[Info]--PreOrderTraverse       : [6 ,3 ,2 ,1 ,5 ,8 ,7 ], CurSize : 7
2023-3--[Info]--InOrderTraverse        : [1 ,2 ,3 ,5 ,6 ,7 ,8 ], CurSize : 7
2023-3--[Info]--PostOrderTraverse      : [1 ,2 ,5 ,3 ,7 ,8 ,6 ], CurSize : 7
2023-3--[Info]--PreOrderTraverseNoRcs  : [6 ,3 ,2 ,1 ,5 ,8 ,7 ], CurSize : 7
2023-3--[Info]--InOrderTraverseNoRcs   : [1 ,2 ,3 ,5 ,6 ,7 ,8 ], CurSize : 7
2023-3--[Info]--PostOrderTraverseNoRcs : [1 ,2 ,5 ,3 ,7 ,8 ,6 ], CurSize : 7
2023-3--[Info]--LevelOrderBinaryTree   : [6 ,3 ,8 ,2 ,5 ,7 ,1 ], CurSize : 7
2023-3--[Info]--SqQueue Data           :
Data           : [1 ,2 ,3 ,0 ,0 ,4 ,5 ,0 ,6 ,0 ,0 ,7 ,0 ,0 ,0 ]
FrontIndex     : 0
RearIndex      : 15
SqQueueLen     : 15
2023-3--[Info]--Init Binary Tree       : OK
2023-3--[Info]--PreOrderTraverse       : [1 ,2 ,3 ,4 ,5 ,6 ,7 ], CurSize : 7
2023-3--[Info]--InOrderTraverse        : [3 ,2 ,5 ,6 ,4 ,7 ,1 ], CurSize : 7
2023-3--[Info]--PostOrderTraverse      : [3 ,6 ,5 ,7 ,4 ,2 ,1 ], CurSize : 7
2023-3--[Info]--PreOrderTraverseNoRcs  : [1 ,2 ,3 ,4 ,5 ,6 ,7 ], CurSize : 7
2023-3--[Info]--InOrderTraverseNoRcs   : [3 ,2 ,5 ,6 ,4 ,7 ,1 ], CurSize : 7
2023-3--[Info]--PostOrderTraverseNoRcs : [3 ,6 ,5 ,7 ,4 ,2 ,1 ], CurSize : 7
2023-3--[Info]--LevelOrderBinaryTree   : [1 ,2 ,3 ,4 ,5 ,7 ,6 ], CurSize : 7
2023-3--[Info]--Init Binary Tree       : OK
2023-3--[Info]--Copy Tree              : OK
2023-3--[Info]--PreOrderTraverse       : [1 ,2 ,3 ,4 ,5 ,6 ,7 ], CurSize : 7
2023-3--[Info]--InOrderTraverse        : [3 ,2 ,5 ,6 ,4 ,7 ,1 ], CurSize : 7
2023-3--[Info]--PostOrderTraverse      : [3 ,6 ,5 ,7 ,4 ,2 ,1 ], CurSize : 7
2023-3--[Info]--Tree Depth             : 4
2023-3--[Info]--Tree Depth             : 5
2023-3--[Info]--Tree Depth             : 5
2023-3--[Info]--Tree Node Num          : 7
2023-3--[Info]--Tree Node Num          : 7
2023-3--[Info]--Tree Node Num          : 7
2023-3--[Info]--Tree Leaves Node Num   : 3
2023-3--[Info]--Tree Leaves Node Num   : 3
2023-3--[Info]--Tree Leaves Node Num   : 3
2023-3--[Info]--Create HaffmanTree     : OK
2023-3--[Info]--HaffmanTree            :
[ Index | Weight | ParentIndex | LeftChildIndex | RightChildIndex ]
[ 0     | 0      | 0           | 0              | 0               ]
[ 1     | 2      | 6           | 0              | 0               ]
[ 2     | 4      | 8           | 0              | 0               ]
[ 3     | 2      | 6           | 0              | 0               ]
[ 4     | 3      | 7           | 0              | 0               ]
[ 5     | 3      | 7           | 0              | 0               ]
[ 6     | 4      | 8           | 1              | 3               ]
[ 7     | 6      | 9           | 4              | 5               ]
[ 8     | 8      | 9           | 6              | 2               ]
[ 9     | 14     | 0           | 7              | 8               ]
2023-3--[Info]--Create HaffmanCode     : OK
2023-3--[Info]--HaffmanCode            :
[ Index | Code    ]
[ 1     | 100     ]
[ 2     | 11      ]
[ 3     | 101     ]
[ 4     | 00      ]
[ 5     | 01      ]
2023-3--[Info]--Destory HaffmanCode    : OK
2023-3--[Info]--Destory HaffmanTree    : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK
2023-3--[Info]--Destroy BT Node        : OK

相关文章:

数据结构与算法基础-学习-18-哈夫曼编码

一、个人理解在远程通讯中&#xff0c;需要把字符转成二进制的字符串进行传输&#xff0c;例如我们需要传输ABCD&#xff0c;我们可以用定长的字符串进行表示&#xff0c;例如:A:00B:01C:02D:03这样可能就造成空间的浪费&#xff0c;我们多存储了一个0号位。那用变长呢&#xf…...

ZMC408CE | 实现“8通道独立PSO”应用场景

一、ZMC408SCAN产品亮点 1.高性能处理器&#xff0c;提升运算速度、响应时间和扫描周期等&#xff1b; 2.一维/二维/三维、多通道视觉飞拍&#xff0c;高速高精&#xff1b; 3.位置同步输出PSO&#xff0c;连续轨迹加工中对精密点胶胶量控制和激光能量控制等&#xff1b; 4…...

QuickJS中JS_SetClassProto方法把JavaScript对象指定为某个类的原型对象

在 QuickJS 中&#xff0c;JS_SetClassProto 方法用于设置一个类的原型对象。这个方法的作用是将一个 JavaScript 对象指定为该类的原型对象&#xff0c;从而定义该类的属性和方法。 具体来说&#xff0c;JS_SetClassProto 方法的第一个参数是指向 QuickJS 引擎执行上下文的指…...

泰克信号发生器特点

泰克信号发生器是一种用于产生各种类型的电子信号的仪器&#xff0c;可以广泛应用于电子、通信、自动化、医疗等领域。泰克信号发生器具有以下特点&#xff1a;多种信号类型&#xff1a;泰克信号发生器可以产生多种类型的电子信号&#xff0c;包括正弦波、方波、三角波、脉冲等…...

贯穿设计模式第四话--里氏替换原则

&#x1f973;&#x1f973;&#x1f973; 茫茫人海千千万万&#xff0c;感谢这一刻你看到了我的文章&#xff0c;感谢观赏&#xff0c;大家好呀&#xff0c;我是最爱吃鱼罐头&#xff0c;大家可以叫鱼罐头呦~&#x1f973;&#x1f973;&#x1f973; 从今天开始&#xff0c;将…...

6501: 鸡兔同笼

描述 一个笼子里面关了鸡和免子(鸡有两只脚,兔子有4只脚,没有例外)。已经知道了笼子里面脚的总数a,问笼子里面至少有多少只动物&#xff0c;至多有多少只动物。 输入 一个正整数a(a<32768)。 输出 包含两个正整数&#xff0c;第一个是最少的动物数&#xff0c;第二个是最多的…...

Linux项目自动化构建工具-make/makefile 介绍及使用

使用背景 在工程中的源文件不计数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;makefile定义一系列 规则来指定什么文件需要先编译&#xff0c;什么文件需要后编译&#xff0c;哪些文件需要重新编译&#xff0c;或者更复杂 的功能操作 makefile带来的好处…...

【云原生|Docker】06-dokcerfile详解

目录 前言 Dockerfile基础示例 Dockerfile简介 1. Dockerfile概念 2. Dokcer镜像分层理解 ​3. Doker build构建原理 Dockerfile参数解析 1. Dokcerfile组成 2. 指令说明 2.1 FROM引入基础镜像 2.2 LABEL 2.3 ENV 2.4 RUN 2.5 COPY 2.6 ADD 2…...

【SCL】博图——先入先出排序法

使用博图SCL语言来实现先入先出排序 前言 使用SCL完成一个先入先出排序 具体要求&#xff1a;最先输入的一个数值&#xff0c;最先输出出来&#xff0c;下面的数自动向前填充&#xff1b; 注&#xff1a;这里可能有两种理解&#xff1a;一是第一个输入的第一个出来&#xff…...

OSPF----特殊区域

目录 OSPF----特殊区域 第一大类----末梢区域&#xff08;Stub Area&#xff09; 完全末梢区域&#xff08;(Totally Stub Area) 第二大类特殊区域----非完全末梢区域&#xff08;NSSA&#xff09; OSPF----特殊区域 第一大类----末梢区域&#xff08;Stub Area&#xff09…...

JVM-类加载

1&#xff1a;类加载机制&#xff1a; 加、验、准、解、初、使、卸 加、烟、准、姐、初、湿、鞋 加载、将class 文件转化为二进制流加载 JVM 内存中并生成一个该类的Class对象验证、Class 文件的字节流中包含的信息是否符合当前虚拟机的要求准备、在方法区中分配这些变量所…...

超详细讲解C语言文件操作!!

超详细讲解C语言文件操作&#xff01;&#xff01;什么是文件文件名文件的打开和关闭文件指针文件的打开和关闭文件的顺序读写文件的随机读写fseekftellrewind文本文件和二进制文件文件读取结束的判定文件缓冲区什么是文件 磁盘上的文件是文件。但是在程序设计中&#xff0c;我…...

linxu学习之进程

文章目录进程程序和进程产生进程销毁进程多进程高并发设计孤儿僵尸守护进程孤儿进程&#xff1a;守护进程(重点)僵尸进程&#xff1a;进程 程序和进程 操作系统可以运行多个程序&#xff0c;那他是如何运行的&#xff1f;实际上&#xff0c;CPU的执行是很快的&#xff0c;而待…...

蓝桥杯真题2

[蓝桥杯 2013 省 B] 连号区间数 题目描述 小明这些天一直在思考这样一个奇怪而有趣的问题&#xff1a; 在 111 ~ NNN 的某个全排列中有多少个连号区间呢&#xff1f;这里所说的连号区间的定义是&#xff1a; 如果区间 [L,R][L, R][L,R] 里的所有元素&#xff08;即此排列的…...

PWM互补输出,以及死区时间计算

本文基于野火例程进行解说 实验内容 本次实验输出一对互补的pwm波&#xff0c;且进行死区时间的计算说明。 代码 互补输出对应的定时器初始化代码&#xff1a; bsp_advance_tim.c /********************************************************************************* fi…...

基于深度学习的海洋动物检测系统(Python+YOLOv5+清新界面)

摘要&#xff1a;基于深度学习的海洋动物检测系统使用深度学习技术检测常见海洋动物&#xff0c;识别图片、视频和实时视频中的海洋动物&#xff0c;方便记录、展示和保存结果。本文详细介绍海洋动物检测系统&#xff0c;在介绍算法原理的同时&#xff0c;给出Python的实现代码…...

C# 计算方差

50&#xff0c;100&#xff0c;100&#xff0c;60&#xff0c;50 计算他们的方差 为了计算这些数的方差&#xff0c;需要进行以下步骤&#xff1a; 1. 计算平均值&#xff0c;即将这些数相加&#xff0c;然后除以它们的数量。 平均值 (50 100 100 60 50) / 5 72 2. 计…...

HJZS电源监视继电器HJZS-E202 AC220V

系列型号&#xff1a; HJZS-E202断电延时继电器 HJZS-E002断电延时继电器 一 应用 HJZS-E202电源监视继电器用于直流或交流操作的各种保护和自动控制的装置中&#xff0c;用以增加触点数量。 二 安装结构 导轨安装9壳体结构&#xff0c;具体尺寸参阅外型尺寸图。 三 产品型号…...

dolphinscheduler 2.0.6 资源中心改造方案二:通过NFS挂载共享目录

目录调度资源中心存储概要安装NFS服务器客户端调度验证关闭SFTP开关&#xff08;可忽略&#xff09;重新上传资源文件worker执行任务验证服务器woker客户端worker其它nfs共享目录的配置文件/etc/exports说明调度资源中心存储概要 针对现有的单机存储可以做哪些扩展&#xff1f;…...

基于集成学习的用户流失预测并利用shap进行特征解释

基于集成学习的用户流失预测并利用shap进行特征解释 小P&#xff1a;小H&#xff0c;如果我只想尽可能的提高准确率&#xff0c;有什么好的办法吗&#xff1f; 小H&#xff1a;优化数据、调参侠、集成学习都可以啊 小P&#xff1a;什么是集成学习啊&#xff0c;听起来就很厉害的…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

css实现圆环展示百分比,根据值动态展示所占比例

代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

Qt Http Server模块功能及架构

Qt Http Server 是 Qt 6.0 中引入的一个新模块&#xff0c;它提供了一个轻量级的 HTTP 服务器实现&#xff0c;主要用于构建基于 HTTP 的应用程序和服务。 功能介绍&#xff1a; 主要功能 HTTP服务器功能&#xff1a; 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...