基于Huffman编码的字符串统计及WPL计算
一、问题描述
问题概括:
给定一个字符串或文件,基于Huffman编码方法,实现以下功能:
1.统计每个字符的频率。
2.输出每个字符的Huffman编码。
3.计算并输出WPL(加权路径长度)。
这个问题要求对Huffman编码算法进行实现和扩展,具体涉及以下步骤:
1.从键盘输入或文件中读取字符串/内容。
2.统计每个字符的出现频率。
3.根据频率构建Huffman树。
4.为每个字符生成对应的Huffman编码。
5.计算WPL并输出。
此外,还要求能够处理文件输入,这涉及到文件读取和解析的逻辑。解决此问题需要熟练掌握Huffman编码算法,包括如何构建Huffman树、如何为字符生成编码以及如何计算WPL。同时,还需要具备基本的文件操作能力,如打开、读取和解析文件内容。
二、分析与设计
(1)设计思想:
数据结构:
- 二叉树:在这段代码中,我们使用了二叉树作为主要的数据结构。每个节点包含一个字符(数据)、一个频率(权重)以及指向左右子节点的指针。这种数据结构使我们能够有效地进行各种操作,如创建树、生成编码和计算WPL。
- 优先队列:我们使用了优先队列(具有自定义比较函数的priority_queue)来帮助创建Huffman树。优先队列能够保证在任何时候,都能以对数时间复杂度获取(并删除)最小元素。
- 哈希表:我们使用了哈希表(map)来存储字符到频率的映射(在创建Huffman树时)以及字符到Huffman编码的映射(在生成Huffman编码时)。
算法思想:
- Huffman编码:Huffman编码是一种用于无损数据压缩的贪心算法。该算法使用字符的频率信息来构建一个最优的前缀编码,使得频率高的字符有更短的编码,频率低的字符有更长的编码,从而达到压缩数据的目的。
- 深度优先搜索:在生成Huffman编码和计算WPL时,我们使用了深度优先搜索(DFS)。DFS是一种用于遍历或搜索树或图的算法。这种算法会尽可能深地搜索树的分支。在这里,我们使用DFS来遍历Huffman树,并在遍历过程中生成Huffman编码或计算WPL。
- 递归:在多个地方,我们使用了递归的方法,如在DFS中遍历二叉树,以及在计算WPL时递归地计算子树的WPL。递归是一种将问题分解为更小子问题的方法,直到问题可以直接解决为止。
(2)设计表示:
主程序各子函数:
- Node(char data, int freq):这是一个构造函数,用于创建一个新的节点。它接受一个字符和一个频率作为参数,并初始化一个新的节点。
- generateHuffmanCode(Node* root, string str, map<char, string>& huffmanCode):这是一个私有方法,用于生成Huffman编码。它递归地遍历Huffman树,并在遍历过程中生成Huffman编码。
- calculateWPL(Node* root, int depth):这是一个私有方法,用于计算WPL(加权路径长度)。它递归地遍历Huffman树,并在遍历过程中计算WPL。
- createHuffmanTree(string text):这是一个公有方法,用于创建Huffman树。它首先统计每个字符出现的频率,然后使用优先队列创建Huffman树。
- generateHuffmanCode():这是一个公有方法,用于生成Huffman编码。它调用generateHuffmanCode(Node* root, string str, map<char, string>& huffmanCode)方法来生成Huffman编码。
- calculateWPL():这是一个公有方法,用于计算WPL。它调用calculateWPL(Node* root, int depth)方法来计算WPL。

图1 函数调用流程图
三、编码说明
完整代码展示:
#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <queue>
using namespace std;// 定义节点类
class Node {
public:char data; // 字符int freq; // 频率Node* left; // 左子节点Node* right; // 右子节点Node(char data, int freq) {this->data = data;this->freq = freq;left = right = nullptr;}
};// 定义比较类
class Compare {
public:bool operator()(Node* l, Node* r) {return l->freq > r->freq;}
};// 定义Huffman树类
class HuffmanTree {
private:Node* root; // Huffman树的根节点// 生成Huffman编码的方法void generateHuffmanCode(Node* root, string str, map<char, string>& huffmanCode) {if (root == nullptr)return;if (!root->left && !root->right) {huffmanCode[root->data] = str;}generateHuffmanCode(root->left, str + "0", huffmanCode);generateHuffmanCode(root->right, str + "1", huffmanCode);}// 计算WPL的方法int calculateWPL(Node* root, int depth) {if (root == nullptr)return 0;if (!root->left && !root->right)return depth * root->freq;return calculateWPL(root->left, depth + 1) + calculateWPL(root->right, depth + 1);}public:// 创建Huffman树的方法map<char, int> createHuffmanTree(string text) {map<char, int> freqMap;for (char ch : text) {freqMap[ch]++;}priority_queue<Node*, vector<Node*>, Compare> pq;for (auto pair : freqMap) {pq.push(new Node(pair.first, pair.second));}while (pq.size() != 1) {Node* left = pq.top(); pq.pop();Node* right = pq.top(); pq.pop();int sum = left->freq + right->freq;Node* newNode = new Node('\0', sum);newNode->left = left;newNode->right = right;pq.push(newNode);}root = pq.top();return freqMap;}// 生成Huffman编码的方法map<char, string> generateHuffmanCode() {map<char, string> huffmanCode;generateHuffmanCode(root, "", huffmanCode);return huffmanCode;}// 计算WPL的方法int calculateWPL() {return calculateWPL(root, 0);}
};int main() {HuffmanTree huffmanTree;string text;string filename;cout << "请输入文件名:";cin >> filename; // 从键盘读取文件名// 从文件读取字符串ifstream file(filename, ios::binary);if (file.is_open()) {text = string((istreambuf_iterator<char>(file)), istreambuf_iterator<char>());file.close();}else {cout << "无法打开文件" << endl;return 1;}// 创建Huffman树并统计每个字符出现的频率map<char, int> freqMap = huffmanTree.createHuffmanTree(text);cout << "字符频率:" << endl;for (auto pair : freqMap) {cout << pair.first << ": " << pair.second << endl;}// 输出每个字符的Huffman编码map<char, string> huffmanCode = huffmanTree.generateHuffmanCode();cout << "Huffman编码:" << endl;for (auto pair : huffmanCode) {cout << pair.first << ": " << pair.second << endl;}// 计算并输出WPLint wpl = huffmanTree.calculateWPL();cout << "WPL: " << wpl << endl;return 0;
}
在开发这个程序的过程中,我经历了一些挑战,这导致我需要进行多次迭代才能得到一个满足需求的版本。以下是我在这个过程中遇到的主要困难和我是如何解决它们的:
- 文件读取:在最初的版本中,我发现程序无法从文件中读取字符串,只能接受键盘输入。这限制了程序的灵活性,因为用户可能希望直接从文件中读取数据,而不是手动输入。
- 版本迭代:为了解决上述问题,我进行了第二次迭代,修改了代码以支持从文件中读取字符串。这个改进使得程序能够处理更复杂的情况,提高了其实用性。
通过这两个版本的迭代,我最终得到了一个可以从文件中读取字符串的程序。虽然这个过程中遇到了一些困难,但每一个挑战都使我有机会学习和成长,也使得最终的程序更加强大和灵活。
四、程序分析

图2 运行结果图
1.时间复杂度:创建Huffman树的时间复杂度是O(n log n),其中n是字符的种类数。这是因为我们需要n次插入操作和n-1次删除操作,每次操作的时间复杂度都是O(log n)。生成Huffman编码和计算WPL的时间复杂度都是O(n),因为我们需要遍历整个Huffman树。
2.空间复杂度:在整个过程中,我们需要存储整个Huffman树,所以空间复杂度是O(n)。此外,我们还需要额外的空间来存储字符到频率的映射和字符到Huffman编码的映射,但这些空间的大小都是常数,所以不影响总的空间复杂度。
五、小结
在解决这个问题的过程中,我深刻地体会到了数据结构,尤其是Huffman树,在解决实际问题中的重要性。Huffman树这种特殊的二叉树结构,以其独特的优雅和高效性,给我留下了深刻的印象。通过这个挑战,我对Huffman树的构建、遍历、修改和查找等操作有了更深入的理解。
我要向我的数据结构老师,表达我最深的感谢。是她的悉心教导让我对数据结构有了深入的理解。她充满热情的教学和专业的知识激发了我对数据结构的热爱,并在我解决这个问题的过程中给予了我宝贵的指导。
此外,我要感谢数据结构这门课程。通过学习这门课程,我不仅掌握了如何更有效地组织和处理数据,还学会了如何分析和解决问题。这个过程对我产生了深远的影响,使我对计算机科学有了更深入的理解。
在解决问题的过程中,我也意识到了一些可以改进的地方。例如,我在创建Huffman树的过程中,未能充分考虑到用户可能输入无效的前序序列。未来,我将对我的代码进行改进,增加对用户输入的验证,以确保创建的Huffman树的有效性。
通过解决这个问题,我对Huffman树有了更深的理解,我的编程技能也得到了提升。在未来,我将继续深入学习和探索数据结构,以更好地应对各种实际问题。再次感谢我的数据结构老师和这门课程,让我有机会领略到数据结构的魅力!
相关文章:
基于Huffman编码的字符串统计及WPL计算
一、问题描述 问题概括: 给定一个字符串或文件,基于Huffman编码方法,实现以下功能: 1.统计每个字符的频率。 2.输出每个字符的Huffman编码。 3.计算并输出WPL(加权路径长度)。 这个问题要求对Huffman编码算…...
处理VS2022中(C/C++)scanf报错问题(3种)
#pragma warning(disable:4996)//第一种:处理scanf在VS2022中报错 #define _CRT_SECURE_NO_WARNINGS//第二种:处理scanf在VS2022中报错 #include<bits/stdc.h> using namespace std; int main() { int a, b; scanf(“%d %d”, &a, &b);//第三种&…...
C#面:Session 喜欢丢值且占内存,Cookis不安全,请问 C# 可以用什么办法代替这两种原始的方法
可以使用 用 ViewState,stateserver。 在 C# 中,ViewState、StateServer 和 Session 都是用于在 Web 应用程序中存储和管理状态信息的机制。它们可以用来在不同的页面之间传递数据或者在同一页面的不同请求之间保持数据的持久性。 ViewState࿱…...
Python并发编程 05 锁、同步条件、信号量、线程队列、生产者消费者模型
文章目录 一、基础概念二、同步锁三、线程死锁和递归锁四、同步条件(event)五、信号量六、线程队列(queue)1、常用方法2、queue模块的三种模式(1)FIFO队列(2)LIFO队列(3&…...
UIKit之UIButton
功能需求: 点击按钮切换按钮的文字和背景图片,同时点击上下左右可以移动图片位置,点击加或减可以放大或缩小图片。 分析: 实现一个UIView的子类即可,该子类包含多个按钮。 实现步骤: 使用OC语言…...
阿里云VOD视频点播流程(2)
二、视频点播 1、入门代码 基于OSS原生SDK上传 ,参考文档:https://help.aliyun.com/zh/vod/user-guide/upload-media-files-by-using-oss-sdks?spma2c4g.11186623.0.0.1f02273fj4lxNJ 视频点播面向开发者提供了丰富的上传方式,其中上传SDK&…...
在Ubuntu上搭建幻兽帕鲁服务器
简介 幻兽帕鲁是一款多人在线角色扮演游戏,玩家可以捕捉和训练各种各样的幻兽,并与其他玩家进行战斗和交易。如果您想拥有自己的幻兽帕鲁服务器,可以按照以下步骤在 Ubuntu 上进行搭建。 准备工作 在开始之前,您需要准备以下几…...
Java中常用类String的不可变性详解
目录 一、String类的概述 二、String不可变性的原理 三、String不可变性的优点 四、String不可变性的缺点及解决方案 五、总结 一、String类的概述 在Java中,String类是一个代表字符串的类。它是Java核心API的一部分,用于处理文本数据。String对象…...
uniapp 自定义App UrlSchemes
需求:外部浏览器H5页面,跳转到uniapp开发的原生app内部。 1、uniapp内部的配置: (1)打开manifest->App常用其他设置,如下,按照提示输入您要设置的urlSchemes: (2&am…...
MSP430环境搭建
1.下载ccs编译器 注意:安装路径和工作路径不能出现中文! 没有说明的步骤就点next即可! 1.1下载适合自己电脑的压缩包。 下载好压缩包后解压,点击有图标进行安装。 1.2创建一个文件夹用于安装编译器位置 选择安装地址࿰…...
【Qt C++实现蓝牙互联】
在 Qt C++ 中实现蓝牙互联可以通过 Qt 的蓝牙模块来实现。下面是一个简单的示例,演示如何在 Qt C++ 中使用蓝牙模块进行蓝牙互联,实现搜索设备、连接设备等功能。 // main.cpp #include <QCoreApplication> #include <QBluetoothDeviceDiscoveryAgent> #include…...
AI绘画已如此厉害,为何我们仍需学习绘画?
在这个AI技术日新月异的时代,AI绘画能力的大幅提升已经不是什么新鲜事。它们以惊人的速度和惊人的精细度完成作品,让不少人感叹:“这是不是意味着,未来绘画将完全由AI接管,人类的创作将变得无足轻重?”在这…...
Android 实现背景图片不被拉伸的效果 9-patch图片 .9图
今天碰到个需求,要求不同手机分辨率背景照片不能被拉伸,除了调用系统方法计算当前屏幕大小这个方法外还有一个就是9-patch图片,可以实现除了icon剩下的部位被缩放。 方法:资源文件右击找到9-patch,转为XXX.9.png照片 …...
Java EE/Jakarta EE范畴一览
Java EE(Java Platform, Enterprise Edition)现在已经改名为Jakarta EE,是一套用于开发企业级应用的标准Java平台。它扩展了Java SE(Standard Edition),添加了支持大规模、多层次、可靠、安全、可伸缩和可管…...
洛谷 P3391:文艺平衡树 ← Splay树模板题
【题目来源】https://www.luogu.com.cn/problem/P3391【题目描述】 您需要写一种数据结构(可参考题目标题),来维护一个有序数列。 其中需要提供以下操作:翻转一个区间,例如原有序序列是 5 4 3 2 1,翻转区间…...
【高校科研前沿】北师大陈晋教授团队在遥感顶刊发表最新成果:ClearSCD模型:在高空间分辨率遥感影像中综合利用语义和变化关系进行语义变化检测
01文章简介 论文名称:The ClearSCD model: Comprehensively leveraging semantics and change relationships for semantic change detection in high spatial resolution remote sensing imagery(ClearSCD模型:在高空间分辨率遥感影像中综合…...
关于YOLO8学习(五)安卓部署ncnn模型--视频检测
教学视频地址 B站 前文 关于YOLO8学习(一)环境搭建,官方检测模型部署到手机 关于YOLO8学习(二)数据集收集,处理 关于YOLO8学习(三)训练自定义的数据集 关于YOLO8学习(四)模型转换为ncnn 简介 本文将会讲解: (1)使用前文生成的ncnn模型,部署到安卓端,并且实…...
从哪些方面可以看出光伏的未来发展好?
光伏发电是一种基于半导体材料的光伏效应将太阳光转化为直流电能的发电技术。近年来,随着全球对可再生能源和环境保护的关注度不断提升,光伏发电行业发展迅速,成为未来能源领域的重要发展方向。 首先,从能源角度来看,光…...
VBA_MF系列技术资料1-605
MF系列VBA技术资料1-605 为了让广大学员在VBA编程中有切实可行的思路及有效的提高自己的编程技巧,我参考大量的资料,并结合自己的经验总结了这份MF系列VBA技术综合资料,而且开放源码(MF04除外),其中MF01-0…...
算法题① —— 数组专栏
1. 滑动窗口 1.1 长度最小的子数组 力扣:https://leetcode.cn/problems/minimum-size-subarray-sum/description/ int minSubArrayLen(int s, vector<int>& nums) {int result INT32_MAX; int sum 0; // 子序列的数值之和int subLength 0; // 子序列…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
