C++Qt6 哈夫曼编码求解 数据结构课程设计 | JorbanS

一、 问题描述

在进行程序设计时,通常给每一个字符标记一个单独的代码来表示一组字符,即编码。在进行二进制编码时,假设所有的代码都等长,那么表示 n 个不同的字符需要 位,称为等长编码。如果每个字符的使用频率相等,那么等长编码无疑是空间效率最高的编码函数,而如果字符出现的频率不同,则可以让频率高的字符采用尽可能短的编码,频率低的字符采用尽可能长的编码,来构造出一种不等长编码,从而获得更好的空间效率。
在设计不等长编码时,要考虑解码的唯一性,如果一组编码中任一编码都不是其他任何一个编码的前缀,那么称这组编码为前缀编码,其保证了编码被解码时的唯一性。霍夫曼树可用于构造最短的前缀编码,即哈夫曼编码(Huffman Code)。
—— OI Wiki

二、 设计思路

以下是项目目录结构图:

HuffmanTree/
├── include/
│   ├── HuffmanNode.h
│   └── HuffmanTree.h
├── src/
│   ├── HuffmanNode.cpp
│   └── HuffmanTree.cpp
├── mainwindow.h
├── mainwindow.ui
├── mainwindow.cpp
└── main.cpp
  1. 创建 HuffmanNode 类:
    HuffmanNode 类用于表示 Huffman 树的节点。
    每个节点包含字符数据、频率以及左右子节点指针。
    为了便于操作,该类包括一个构造函数,用于初始化节点的数据成员。
  2. 创建 CompareNodes 结构体:
    CompareNodes 结构体是一个自定义的比较器。
    用于在优先队列中比较两个 HuffmanNode 指针的频率,以便按频率升序排序节点。
  3. 创建 HuffmanTree 类:
    HuffmanTree 类表示 Huffman 树的结构和操作。
    构造函数接受一个映射(map)参数,其中包含字符和对应的频率,然后调用 buildTree 函数构建 Huffman 树。
  4. 实现 buildTree 函数:
    buildTree 函数用于根据字符频率构建 Huffman 树。
    使用优先队列(最小堆)来维护节点,每个节点代表一个字符及其频率。
    循环从优先队列中弹出两个最小频率的节点,然后创建一个新的父节点,将这两个节点作为子节点,父节点的频率为子节点频率之和。
    将新创建的父节点放回优先队列,重复这个过程直到队列中只剩下一个节点,即 Huffman 树的根节点。
  5. 实现 generateCodes 函数:
    generateCodes 函数是一个递归函数,用于遍历 Huffman 树并生成字符的 Huffman 编码。
    从根节点开始,沿着左子树的路径添加 “0”,沿着右子树的路径添加 “1”。
    当遇到叶子节点时,将字符和路径编码存储在一个字符到编码的映射中。

三、 数据结构设计

  1. 哈夫曼节点类 HuffmanNode:
    HuffmanNode 类用于表示哈夫曼树的节点,包括字符数据、频率以及左右子节点指针。
    构造函数初始化节点的数据、频率和子节点指针。
  2. 比较器结构 CompareNodes:
    CompareNodes 结构用于比较两个 HuffmanNode 指针,按照频率从小到大的顺序排序,以便在优先队列中使用。
  3. 哈夫曼树类 HuffmanTree:
    HuffmanTree 类用于构建哈夫曼树。
    构造函数接受一个 map<char, int> 参数,其中包含字符和它们的频率信息,并调用 buildTree 函数构建哈夫曼树。
    buildTree 使用优先队列(最小堆)来构建哈夫曼树,首先将字符频率转化为节点,然后反复合并频率最低的两个节点,直到只剩下一个根节点。
    getCodes 函数生成字符到编码的映射。
  4. 私有函数 generateCodes:
    generateCodes 用于递归地生成字符到编码的映射,遍历哈夫曼树,构建每个字符的编码。
    在遇到叶子节点时将字符和编码存储在映射中。

四、 功能函数设计

  1. 包含头文件和命名空间:代码包含了 、 和 头文件,并使用 using namespace std; 来引入标准命名空间。
  2. 用于比较 HuffmanNode 指针的比较器 CompareNodes:定义了一个用于优先队列比较的自定义比较器,按照节点的频率从小到大进行比较。
  3. buildTree 构建哈夫曼树的主要逻辑,使用优先队列来合并频率最低的节点,直到只剩下一个根节点。
  4. getCodes 用于获取字符到哈夫曼编码的映射。
  5. generateCodes:递归,用于生成字符到哈夫曼编码的映射,从根节点开始遍历树。

五、 程序代码

// main.cpp#include "mainwindow.h"
#include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);MainWindow w;w.setWindowTitle("DS 课程设计 zdy229074447");w.show();return a.exec();
}
// mainwindows.h#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QtWidgets>
#include <map>
#include "include/HuffmanTree.h"QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACEclass MainWindow: public QMainWindow {Q_OBJECT
public:MainWindow(QWidget *parent = nullptr);~MainWindow();void onButtonConfirmClicked();void onButtonResetClicked();
private:Ui::MainWindow *ui;QTableWidget* tableWidget;QLineEdit* charInput;QLineEdit* frequencyInput;QPushButton* buttonConfirm, *buttonReset;HuffmanTree* huffmanTree;map<char, int> frequencies;void updateTable();
};#endif // MAINWINDOW_H
// mainwindow.cpp#include <QtWidgets>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "include/HuffmanNode.h"
#include "include/HuffmanTree.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);// 初始化输入框和按钮tableWidget = this->findChild<QTableWidget *>("Table_Result");charInput = this->findChild<QLineEdit *>("Char_Input");frequencyInput = this->findChild<QLineEdit *>("Frequency_Input");buttonConfirm = this->findChild<QPushButton *>("Button_Confirm");buttonReset = this->findChild<QPushButton *>("Button_Reset");// 连接按钮点击事件到槽函数Zconnect(buttonConfirm, &QPushButton::clicked, this, &MainWindow::onButtonConfirmClicked);connect(buttonReset, &QPushButton::clicked, this, &MainWindow::onButtonResetClicked);// 初始化哈夫曼树huffmanTree = nullptr; // 在这里初始化为空// 设置表格的列数和表头tableWidget->setColumnCount(3);tableWidget->setHorizontalHeaderLabels({"字符", "频次", "哈夫曼编码"});}void MainWindow::onButtonResetClicked() {for (auto pair: frequencies) {frequencies[pair.first] = 0;}delete huffmanTree;huffmanTree = new HuffmanTree(frequencies);updateTable();
}void MainWindow::onButtonConfirmClicked() {QString charText = charInput->text();QString freqText = frequencyInput->text();if (!charText.isEmpty() && !freqText.isEmpty()) {char character = charText.at(0).toLatin1(); // 获取第一个字符int frequency = freqText.toInt();// 创建哈夫曼树(如果尚未创建)if (huffmanTree == nullptr) {frequencies[character] = frequency; // 使用 [] 操作符添加键值对huffmanTree = new HuffmanTree(frequencies);} else {// 更新频率frequencies[character] += frequency;huffmanTree->buildTree(frequencies); // 重新构建哈夫曼树}// 更新表格内容updateTable();}
}void MainWindow::updateTable() {// 清空表格内容tableWidget->clearContents();tableWidget->setRowCount(0);// 获取哈夫曼树的编码映射map<char, string> codes = huffmanTree->getCodes();// 遍历编码映射并更新表格int row = 0;for (auto pair: codes) {tableWidget->insertRow(row);QTableWidgetItem* charItem = new QTableWidgetItem(QString(pair.first));QTableWidgetItem* frequencyItem = new QTableWidgetItem(QString::number(frequencies[pair.first]));QTableWidgetItem* codeItem = new QTableWidgetItem(QString::fromStdString(pair.second));tableWidget->setItem(row, 0, charItem);tableWidget->setItem(row, 1, frequencyItem);tableWidget->setItem(row, 2, codeItem);row++;}
}MainWindow::~MainWindow() {delete ui;
}
// HuffmanNode.h#ifndef HUFFMANNODE_H
#define HUFFMANNODE_Hclass HuffmanNode {
public:char data;int frequency;HuffmanNode *left, *right;HuffmanNode(char data, int frequency);
};#endif // HUFFMANNODE_H
// HuffmanTree.h#ifndef HUFFMANTREE_H
#define HUFFMANTREE_H#include "HuffmanNode.h"
#include <map>
#include <string>using namespace std;// 哈夫曼树类
class HuffmanTree {
private:
public:void generateCodes(HuffmanNode* node, string code, map<char, string>& codes);HuffmanNode* root;HuffmanTree(map<char, int> frequencies);void buildTree(map<char, int> frequencies);map<char, string> getCodes();
};#endif // HUFFMANTREE_H
// HuffmanNode.cpp#include "../include/HuffmanNode.h"HuffmanNode::HuffmanNode(char data, int frequency) {this->data = data;this->frequency = frequency;this->left = nullptr;this->right = nullptr;
}
// HuffmanTree.cpp#include "../include/HuffmanTree.h"
#include <vector>
#include <queue>// 用于比较 HuffmanNode 指针的比较器
struct CompareNodes {bool operator()(HuffmanNode* left, HuffmanNode* right) {return left->frequency > right->frequency;}
};HuffmanTree::HuffmanTree(map<char, int> frequencies) {buildTree(frequencies);
}void HuffmanTree::buildTree(map<char, int> frequencies) {priority_queue<HuffmanNode*, vector<HuffmanNode*>, CompareNodes> heap;// 将字符频率构建为节点,并将它们添加到优先队列for (auto entry: frequencies) {HuffmanNode* node = new HuffmanNode(entry.first, entry.second);heap.push(node);}// 构建哈夫曼树while (heap.size() > 1) {HuffmanNode* left = heap.top();heap.pop();HuffmanNode* right = heap.top();heap.pop();// 创建一个新节点作为父节点,其频率为左右子树的频率之和HuffmanNode* parent = new HuffmanNode('\0', left->frequency + right->frequency);parent->left = left;parent->right = right;heap.push(parent);}// 根节点就是哈夫曼树的根root = heap.top();
}map<char, string> HuffmanTree::getCodes() {map<char, string> codes;generateCodes(root, "", codes);return codes;
}void HuffmanTree::generateCodes(HuffmanNode* node, string code, map<char, string>& codes) {if (node == nullptr) return;// 叶子节点,将字符和编码存储在映射中if (node->data != '\0') codes[node->data] = code;generateCodes(node->left, code + "0", codes);generateCodes(node->right, code + "1", codes);
}
// mainwindows.ui<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>MainWindow</class><widget class="QMainWindow" name="MainWindow"><property name="geometry"><rect><x>0</x><y>0</y><width>451</width><height>582</height></rect></property><property name="windowTitle"><string>MainWindow</string></property><widget class="QWidget" name="centralwidget"><widget class="QPushButton" name="Button_Confirm"><property name="geometry"><rect><x>260</x><y>10</y><width>111</width><height>41</height></rect></property><property name="styleSheet"><string notr="true">font: 10pt &quot;Microsoft YaHei UI&quot;;</string></property><property name="text"><string>添加</string></property></widget><widget class="QLineEdit" name="Char_Input"><property name="geometry"><rect><x>50</x><y>10</y><width>51</width><height>41</height></rect></property><property name="styleSheet"><string notr="true">font: 10pt &quot;Microsoft YaHei UI&quot;;</string></property><property name="text"><string/></property></widget><widget class="QLineEdit" name="Frequency_Input"><property name="geometry"><rect><x>140</x><y>10</y><width>111</width><height>41</height></rect></property><property name="styleSheet"><string notr="true">font: 10pt &quot;Microsoft YaHei UI&quot;;</string></property><property name="text"><string/></property></widget><widget class="QTableWidget" name="Table_Result"><property name="geometry"><rect><x>20</x><y>60</y><width>411</width><height>471</height></rect></property></widget><widget class="QPushButton" name="Button_Reset"><property name="geometry"><rect><x>380</x><y>10</y><width>51</width><height>41</height></rect></property><property name="styleSheet"><string notr="true">font: 10pt &quot;Microsoft YaHei UI&quot;;</string></property><property name="text"><string>重置</string></property></widget><widget class="QLabel" name="label"><property name="geometry"><rect><x>20</x><y>20</y><width>41</width><height>19</height></rect></property><property name="text"><string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;字符&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string></property></widget><widget class="QLabel" name="label_2"><property name="geometry"><rect><x>110</x><y>20</y><width>41</width><height>19</height></rect></property><property name="text"><string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;频次&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string></property></widget></widget><widget class="QStatusBar" name="statusbar"/><widget class="QMenuBar" name="menubar"><property name="geometry"><rect><x>0</x><y>0</y><width>451</width><height>24</height></rect></property><widget class="QMenu" name="menu"><property name="title"><string>哈夫曼编码求解</string></property></widget><addaction name="menu"/></widget></widget><resources/><connections/>
</ui>

六、 运行结果及分析

在这里插入图片描述

多次添加后,如左图;重置操作后,如右图
所需实现的功能达成,并且可以动态更新。

七、 设计心得

使用了C++的面向对象编程来将Huffman编码的各个组成部分封装成类,这有助于代码的模块化和可维护性。合理地使用了STL容器和数据结构,如map和priority_queue,来简化实现。通过C++Qt构建图形化GUI界面,简化了用户操作,提升了交互属性。

八、 参考资料

霍夫曼树 - OI Wiki (oi-wiki.org) https://oi-wiki.org/ds/huffman-tree/

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【hyperledger-fabric】部署和安装

简介 对hyperledger-fabric进行安装&#xff0c;话不多说&#xff0c;直接开干。但是需要申明一点&#xff0c;也就是本文章全程是开着加速器进行的资源操作&#xff0c;所以对于没有开加速器的情况可能会由于网络原因导致下载资源失败。 资料提供 1.官方部署文档在此&#…

车载电子电器架构 —— 电子电气系统开发角色定义

车载电子电器架构 —— 电子电气系统开发角色定义 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 注:本文12000字,深度思考者进!!! 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的…

Redis7.2.3(Windows版本)

1、解压 &#xfeff; &#xfeff; 2、设置密码 &#xff08;1&#xff09; 右击编辑redis.conf文件&#xff1a; &#xfeff; &#xff08;2&#xff09; 设置密码。 &#xfeff; 3、测试密码是否添加成功 &#xfeff; 如上图所示&#xff0c;即为成功。 4、设置…

阿里云 ACK 云上大规模 Kubernetes 集群高可靠性保障实战

作者&#xff1a;贤维 马建波 古九 五花 刘佳旭 引言 2023 年 7 月&#xff0c;阿里云容器服务 ACK 成为首批通过中国信通院“云服务稳定运行能力-容器集群稳定性”评估的产品&#xff0c; 并荣获“先进级”认证。随着 ACK 在生产环境中的采用率越来越高&#xff0c;稳定性保…

第7课 利用FFmpeg将摄像头画面与麦克风数据合成后推送到rtmp服务器

上节课我们已经拿到了摄像头数据和麦克风数据&#xff0c;这节课我们来看一下如何将二者合并起来推送到rtmp服务器。推送音视频合成流到rtmp服务器地址的流程如下&#xff1a; 1.创建输出流 //初始化输出流上下文 avformat_alloc_output_context2(&outFormatCtx, NULL, &…

dmetl5授权查看与更新

1.查看dmetl5授权到期时间 需要登录管理端&#xff0c;菜单栏选择“管理”-“license管理”即可查看授权到期时间。如下图&#xff1a; 2.dmetl5更新授权的方法 dmetl5的<安装目录>\scheduler\config路径下&#xff0c;默认会有一个trail.key的文件&#xff0c;删除后&am…

Java学习苦旅(十六)——List

本篇博客将详细讲解Java中的List。 文章目录 预备知识——初识泛型泛型的引入泛型小结 预备知识——包装类基本数据类型和包装类直接对应关系装包与拆包 ArrayList简介ArrayList使用ArrayList的构造ArrayList常见操作ArrayList遍历 结尾 预备知识——初识泛型 泛型的引入 我…

八大算法排序@选择排序(C语言版本)

目录 选择排序概念算法思想示例步骤1步骤2步骤...n最后一步 代码实现时间复杂度空间复杂度特性总结 选择排序 概念 选择排序&#xff08;Selection Sort&#xff09;是一种简单直观的排序算法。基本思想是在未排序的序列中找到最小&#xff08;或最大&#xff09;元素&#xf…

Android studio ViewPager2应用设计

一、ViewPager2应用场景&#xff1a; ViewPager2是一个功能强大的滑动容器&#xff0c;提供灵活的页面切换和布局定制功能&#xff0c;使得应用程序界面更加丰富和交互性强&#xff0c;主要应用于以下场景&#xff1a; 1&#xff09;、实现引导页或欢迎页&#xff1a;ViewPag…

【安卓的签名和权限】

Android 编译使用哪个key签名&#xff1f; 一看Android.mk 在我们内置某个apk的时候都会带有Android.mk&#xff0c;这里面就写明了该APK使用的是什么签名&#xff0c;如&#xff1a; LOCAL_CERTIFICATE : platform表明使用的是platform签名 LOCAL_CERTIFICATE : PRESIGNED…

Java ArrayList在遍历时删除元素

文章目录 1. Arrays.asList()获取到的ArrayList只能遍历&#xff0c;不能增加或删除元素2. java.util.ArrayList.SubList有实现add()、remove()方法3. 遍历集合时对元素重新赋值、对元素中的属性赋值、删除元素、新增元素3.1 普通for循环3.2 增强for循环3.3 forEach循环3.4 str…

TSConfig 配置(tsconfig.json)

详细总结一下TSConfig 的相关配置项。个人笔记&#xff0c;仅供参考&#xff0c;欢迎批评指正&#xff01; 根目录 {/* 指定编译文件/目录 */"files": [], // 指定被编译的文件"include": [], // 指定被编译文件所在的目录"exclude": [], // 指…

【CFP-专栏2】计算机类SCI优质期刊汇总(含IEEE/Top)

一、计算机区块链类SCI-IEEE 【期刊概况】IF:4.0-5.0, JCR2区&#xff0c;中科院2区&#xff1b; 【大类学科】计算机科学&#xff1b; 【检索情况】SCI在检&#xff1b; 【录用周期】3-5个月左右录用&#xff1b; 【截稿时间】12.31截稿&#xff1b; 【接收领域】区块链…

零基础开发 React+ TS 后台实战课程介绍

下面所有效果均从零开始进行演示开发&#xff1a; 效果演示图&#xff1a; 登录页 仪表盘首页搭建 引导页制作 React 国际化外语切换 React Ant-deign 组件拆分增删改查 涉及知识点 React 图片上传分页查询组件拆分遮罩层演示数据隔离 React 用户管理 React 公告管理 发布…

Github 2023-12-31 开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2023-12-31统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量TypeScript项目3Swift项目1Java项目1HTML项目1Astro项目1Python项目1C项目1Dart项目1Jupyter Notebook项目1C项…

java spring boot 获取resource目录下的文档

主要代码 String filePath"templates/test.xls" ClassPathResource classPathResource new ClassPathResource(filePath); InputStream inputStream classPathResource.getInputStream();目录 主要目录存放再这 代码案例 public void downloadTemplate( HttpS…

3 - 字段约束|MySQL索引|MySQL用户管理

字段约束&#xff5c;MySQL索引&#xff5c;MySQL用户管理 字段约束主键外键 MySQL索引索引介绍优缺点索引使用规则索引的分类索引的管理 用户管理用户授权权限撤销 用户权限追加user表的使用 字段约束 设置在表头上&#xff0c;用来限制字段赋值 包括&#xff1a; 是否允许给…

Modbus 通信协议 二

Modbus 常用缩写 通用Modbus帧结构 -应用数据单元&#xff08;ADU&#xff09; Modbus数据模型 Modbus ADU 和 PDU 的长度 Modbus PDU结构 串行链路上的 Modbus 帧结构 Modbus 地址规则 ASCLL 模式 和 RTU 模式的比较 RTU 模式 RTU 模式位序列 帧格式 帧的标识与鉴别 CRC 循环冗…

Vue3-30-路由-嵌套路由的基本使用

什么是嵌套路由 嵌套路由 &#xff1a;就是一个组件内部还希望展示其他的组件&#xff0c;使用嵌套的方式实现页面组件的渲染。 就像 根组件 通过路由渲染 普通组件一样&#xff0c;嵌套路由也是一样的道理。 嵌套路由的相关关键配置 1、<router-view> 标签 声明 被嵌套组…