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

【C语言】C语言 哈夫曼编码传输(源码+数据文件)【独一无二】

请添加图片描述


👉博__主👈:米码收割机
👉技__能👈:C++/Python语言
👉专__注👈:专注主流机器人、人工智能等相关领域的开发、测试技术。


C语言 哈夫曼编码传输(源码+数据文件)【独一无二】


目录

  • C语言 哈夫曼编码传输(源码+数据文件)【独一无二】
  • 一、设计要求
  • 二、设计思路
    • 2. 核心数据结构与辅助函数
      • 2.1 数据结构定义
      • 2.2 最小堆辅助函数
    • 3. 哈夫曼树的构建与编码生成
      • 3.1 构建哈夫曼树
      • 3.2 生成哈夫曼编码表
    • 4. 文件编码、解码与验证
      • 4.1 编码文件
      • 4.2 解码文件
      • 4.3 文件一致性对比
    • 5. 主函数及整体工作流程


一、设计要求

问题4:某系统在通信联络中需要传送一个英文文件,该文件包含26个英文字母和空格等字符。请自行准备一个文本文件,要求这个文件中总符号数不少于10000个。要求运用哈夫曼编码方法,对该文本文件进行编码和解码,并校验解码后的文本正确性。请编写具体的计算机程序

在这里插入图片描述


二、设计思路

在这里插入图片描述

整个程序可以分为以下几个主要部分:

  1. 文件操作与预处理

    • 获取文件大小(getFileSize())。
    • 统计输入文件中每个字符的出现频率,为构建哈夫曼树做准备。
  2. 核心数据结构与辅助工具

    • 定义哈夫曼树节点(HuffmanTreeNode)和最小堆(MinHeap)的数据结构。
    • 实现最小堆的基本操作:插入、交换、向下调整(minHeapify())与提取最小节点(extractMin())。
  3. 哈夫曼树构建与编码表生成

    • 根据字符频率构建哈夫曼树,采用贪心策略不断合并频率最低的两个节点。
    • 遍历哈夫曼树生成每个字符的二进制编码(buildCodes()),并存入全局编码表 huffmanCode 中。
  4. 文件编码与解码

    • 通过编码表对原始文件进行编码(encodeFile()),将字符转换成由 0 和 1 组成的字符串保存到输出文件中。
    • 利用构建好的哈夫曼树对编码后的文件进行解码(decodeFile()),还原出原始文本信息。
  5. 验证与性能统计

    • 对比原始文件和解码后的文件(compareFiles())确保解码准确性。
    • 计算文件压缩率,展示压缩效果。

2. 核心数据结构与辅助函数

2.1 数据结构定义

程序中定义了两个核心数据结构,在哈夫曼编码中起到重要作用:

  • 哈夫曼树节点(HuffmanTreeNode)

    每个节点存储一个字符及其出现频率,同时包含左右孩子指针。例如:

    typedef struct HuffmanTreeNode {
        unsigned char ch;   // 字符
        unsigned freq;      // 字符频率
        struct HuffmanTreeNode *left, *right;
    } HuffmanTreeNode;
    
  • 最小堆(MinHeap)

    最小堆用于快速找到频率最小的节点,在构建哈夫曼树过程中非常关键:

    typedef struct MinHeap {
        int size;
        int capacity;
        HuffmanTreeNode** array;
    } MinHeap;
    

2.2 最小堆辅助函数

程序实现了常用的最小堆操作,包括节点交换、向下调整(minHeapify())、插入节点(insertMinHeap())和提取最小节点(extractMin())。
例如,向下调整函数保证了堆的性质:

void minHeapify(MinHeap* minHeap, int idx) {
    int smallest = idx;
    int left = 2 * idx + 1;
     // 代码略....
    if (right < minHeap->size &&
        minHeap->array[right]->freq < minHeap->array[smallest]->freq) {
        smallest = right;
    }
    if (smallest != idx) {
        swapNode(&minHeap->array[smallest], &minHeap->array[idx]);
        minHeapify(minHeap, smallest);
    }
}

在这里插入图片描述


3. 哈夫曼树的构建与编码生成

3.1 构建哈夫曼树

函数 buildHuffmanTree() 根据统计好的字符频率构建哈夫曼树,其基本流程如下:

  1. 统计有效字符数量
    遍历频率表,统计每个出现过的字符个数以确定最小堆的容量。

  2. 构建最小堆并插入所有字符节点
    为每个出现的字符创建一个节点,并插入到最小堆中。

  3. 合并最小节点
    循环执行以下操作:

    • 提取两个最小频率的节点。
    • 创建一个新节点,其频率为两节点频率之和,新节点左右指针指向这两个节点。
    • 将新节点重新插入堆中,直到堆中只剩下一个节点,该节点即为哈夫曼树的根。

部分代码示例如下:

while (minHeap->size > 1) {
    HuffmanTreeNode* left = extractMin(minHeap);
    HuffmanTreeNode* right = extractMin(minHeap);
    HuffmanTreeNode* top = createNode('\0', left->freq + right->freq);
    top->left = left;
    top->right = right;
    insertMinHeap(minHeap, top);
}

3.2 生成哈夫曼编码表

利用已经构建好的哈夫曼树,通过递归方式生成每个字符的编码:

  • 当递归向左(代表二进制“0”)或右(代表二进制“1”)不断累积编码,直到遇到叶子节点;
  • 到达叶子节点后,将生成的二进制字符串保存到全局编码表 huffmanCode 中。

函数示例:

void buildCodes(HuffmanTreeNode* root, char* code, int length) {
    if (!root) return;
     // 代码略....
    code[length] = '0';
    buildCodes(root->left, code, length + 1);
    code[length] = '1';
    buildCodes(root->right, code, length + 1);
}

在这里插入图片描述


4. 文件编码、解码与验证

4.1 编码文件

函数 encodeFile() 打开原始文件,并对每个字符用对应的哈夫曼编码替换后写入到编码文件中。
关键代码:

while ((ch = fgetc(fin)) != EOF) {
    fputs(huffmanCode[ch], fout);
}

4.2 解码文件

函数 decodeFile() 根据编码文件中的 0/1 流,利用哈夫曼树反向遍历解码还原每个字符,直到完整还原出原始文本:

HuffmanTreeNode* curr = root;
while ((bit = fgetc(fin)) != EOF) {
    if (bit == '0')
        curr = curr->left;
    else if (bit == '1')
        curr = curr->right;
    // 到达叶子节点,输出字符
    if (!curr->left && !curr->right) {
        fputc(curr->ch, fout);
        curr = root;
    }
}

4.3 文件一致性对比

函数 compareFiles() 将原始文件和解码后的文件进行字节级对比,确保解码过程没有任何错误:

do {
    c1 = fgetc(f1);
    c2 = fgetc(f2);
    if (c1 != c2) { /* 不同 */
        fclose(f1);
        fclose(f2);
        return 0;
    }
} while (c1 != EOF && c2 != EOF);

在这里插入图片描述


5. 主函数及整体工作流程

主函数 main() 整合了上述所有步骤,其主要流程如下:

  1. 预处理与频率统计

    • 判断原始文件是否存在,读取文件大小。
    • 遍历文件,统计每个字符的出现频率,填充频率表 freqTable
  2. 构建哈夫曼树与生成编码表

    • 调用 buildHuffmanTree() 构建哈夫曼树;
    • 通过 buildCodes() 生成用于编码的哈夫曼编码表。
  3. 执行编码与解码

    • 使用 encodeFile() 对原始文件进行编码;
    • decodeFile() 将编码后文件解码为还原文件。
  4. 结果验证与性能评估

    • 调用 compareFiles() 检查解码文件与原文件是否一致;
    • 计算压缩率,并打印原始大小、压缩后大小及压缩率。

主函数示例代码:

int main() {
    const char* inputFile    = "input.txt";    // 原始文件
    const char* encodedFile  = "encoded.txt";  // 编码结果(0/1串)
    const char* decodedFile  = "decoded.txt";  // 解码结果

    // 1) 读取原文件大小
        // 代码略....

    // 3) 构建哈夫曼树
    HuffmanTreeNode* root = buildHuffmanTree(freqTable);

    // 代码略....

    printf("原文件大小:%ld 字节\n", originalSize);
    printf("压缩后文件大小:%ld 字节\n", compressedSize);
    printf("压缩率:%.2f%%\n", ratio);
    printf("解压后文本与原文本相同:%s\n", isSame ? "True" : "False");

    // 释放哈夫曼树
    freeHuffmanTree(root);

    return 0;
}

运行结果:
在这里插入图片描述

---

相关文章:

  • 2025年人工智能与教育系统国际学术会议(ICAIES 2025)
  • postgres源码学习之简单sql查询
  • Java开发实习面试笔试题(含答案)
  • 【信息系统项目管理师】专业英语重点词汇大汇总
  • 数字电路中的焊接技术
  • MyBatis XML映射文件中的批量插入和更新
  • 模电知识点总结(2)
  • 信息安全管理体系认证:赋能组织应对数字时代的风险与挑战
  • 【含文档+PPT+源码】基于微信小程序的猎兔汽车保养维修美容服务平台的设计与实现
  • INA219电流、电压、功率测量芯片应用
  • Ollama 本地GUI客户端:为DeepSeek用户量身定制的智能模型管理与交互工具
  • 斐波那契数列模型:在动态规划的丝绸之路上追寻斐波那契的足迹(上)
  • 在VS-qt的程序中,后期增加PCH预编译功能,提高编译速度
  • 【练习】【二分】力扣热题100 34. 在排序数组中查找元素的第一个和最后一个位置
  • 蓝桥杯 Java B 组之设计 LRU 缓存
  • 【DeepSeek系列】04 DeepSeek-R1:带有冷启动的强化学习
  • 吊舱夜视与测距功能:核心技术、应用与未来展望
  • LC电路的作用是什么?
  • Conda 常用命令全解析
  • 大道至简 少字全意 易经的方式看 缓存 mybatis缓存 rendis缓存场景 案例
  • 张涌任西安市委常委,已卸任西安市副市长职务
  • 4月新增社融1.16万亿,还原地方债务置换影响后信贷增速超过8%
  • 阿坝州委书记徐芝文已任四川省政府党组成员
  • 乌拉圭前总统何塞·穆希卡去世
  • 美国4月CPI同比上涨2.3%低于预期,为2021年2月来最小涨幅
  • 持续8年仍难终了的纠纷:败诉方因拒执罪被立案,胜诉方银行账户遭冻结