C程序实践 哈夫曼(Huffman)树代码

2024-05-24 22:38

本文主要是介绍C程序实践 哈夫曼(Huffman)树代码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

/*
Slyar
2009.10.29
*/#include <stdio.h>
#include <stdlib.h>
#include <io.h>#define N 255
#define M 2*N - 1/* 运行成功标记 */
int ok = 0;/* 保存原文件名 */
char file[20] = {};/* 哈夫曼树节点类型 */
typedef struct
{int data; /* 字符值 */int weight; /* 权重 */int parent; /* 双亲结点 */int lchild; /* 左孩子结点 */int rchild; /* 右孩子结点 */
}Tree;/* 哈夫曼编码类型 */
typedef struct
{/* 存放哈夫曼码 */char cd[N]; int start;
}Code;/* 生成节点及编码数组 */
Tree ht[M];
Code hcd[N];/* 函数声明 */
int cmp(const void*, const void*);
int NumberOfChar();
void Reset();
void InputFile();
void Encode(int);
void Decode(int);
void OutputFile(int);
void PrintHuffmanCode(int);
void CreateHT(int);
void CreateHCode(int);/* 主函数 */
int main()
{int x = 0;int n = 0;char ch;while(1){system("cls");printf("1. 读入原文件\n");printf("2. 在屏幕上打印哈夫曼代码表\n");printf("3. 编码原文件\n");printf("4. 解码原文件\n");printf("5. 退出\n");printf("Input 1-5:");scanf("%d", &x);switch(x){case 1:Reset();InputFile();if (ok){/* 排序使得有效字符在前面 */qsort(ht, N, sizeof(Tree), cmp);/* 记下有效字符的个数 */n = NumberOfChar();CreateHT(n);CreateHCode(n);OutputFile(n);system("pause");}break;case 2:system("cls");if (ok){PrintHuffmanCode(n);}else{printf("原文件尚未读入!\n");}system("pause");break;case 3:system("cls");if (ok){Encode(n);}else{printf("原文件尚未读入!\n");}system("pause");break;case 4:system("cls");if (ok){Decode(n);}else{printf("原文件尚未读入!\n");}system("pause");break;case 5:return 0;default:/* 防止输入错误序号,刷新缓冲区 */fflush(stdin);}}return 0;
}/* 快速排序比较函数 */
int cmp(const void *a ,const void *b)
{return (*(Tree *)a).weight < (*(Tree *)b).weight ? 1 : -1;
}/* 统计有效的字符数量 */
int NumberOfChar()
{int i, num = 0;for (i = 0; i < N; i++){if (ht[i].weight > 0) num++;}return num;
}/* 初始化哈夫曼树 */
void Reset()
{int i;for (i = 0; i < M; i++){ht[i].weight = 0;ht[i].parent = -1;ht[i].lchild = -1;ht[i].rchild = -1;}
}/* 读入文件内容 */
void InputFile()
{FILE *fp;char ch;system("cls");printf("请输入原文件名:");fflush(stdin);scanf("%s", file);/* 打开原文件 */if ((fp = fopen(file, "rt")) == NULL){printf("找不到原文件 %s!\n", file);ok = 0;system("pause");return;}/* 读入字符并处理权重 */while (fscanf(fp, "%c", &ch) != EOF){ht[ch].data = ch;ht[ch].weight++;}/* 关闭文件指针 */fclose(fp);printf("原文件 %s 读入成功!\n", file);ok = 1;
}/* 编码 */
void Encode(int n)
{int i, k;char ch;FILE *fp1, *fp2;/* 利用哈夫曼代码表进行编码 */if (access("Huffman_Code.txt",0) != 0){printf("找不到代码表 Huffman_Code.txt !\n");return;}/* 打开要编码的原文件 */if ((fp1 = fopen(file, "rt")) == NULL){printf("找不到原文件 %s !\n", file);return;}/* 生成编码文件 */if ((fp2 = fopen("Encode.txt", "wt+")) == NULL){printf("编码文件 Encode.txt 创建失败!\n");return;}/* 一个字符一个字符替换 */while (fscanf(fp1, "%c", &ch) != EOF){for (i = 0; i < n; i++){if (ht[i].data == ch){for (k = hcd[i].start; k <= n; k++){fprintf(fp2, "%c", hcd[i].cd[k]);}}}}/* 关闭文件指针 */fclose(fp1);fclose(fp2);printf("编码成功,结果在 Encode.txt 中!\n");
}/* 解码 */
void Decode(int n)
{int i, k;char ch;FILE *fp1, *fp2;/* 打开要解码的文件 */if ((fp1 = fopen("Encode.txt", "rt")) == NULL){printf("找不到编码文件 Encode.txt!\n");return;}/* 生成解码文件 */if ((fp2 = fopen("Decode.txt", "wt+")) == NULL){printf("解码文件 Decode.txt 创建失败!\n");return;}/* 利用哈夫曼树解码 */i = 2 * n - 2;while (fscanf(fp1, "%c", &ch) != EOF){if (ch == '0'){i = ht[i].lchild;}else{i = ht[i].rchild;}/* 找到叶子节点为止 */if (ht[i].lchild == -1){fprintf(fp2, "%c", ht[i].data);/* 继续从根节点开始查找 */i = 2 * n - 2;}}/* 关闭文件指针 */fclose(fp1);fclose(fp2);printf("解码成功,结果在 Decode.txt 中!\n");
}/* 输出哈弗曼编码到文件 */
void OutputFile(int n)
{FILE *fp;int i, k;/* 生成哈夫曼代码表文件 */if ((fp = fopen("Huffman_Code.txt", "wt+")) == NULL){printf("代码表文件 Huffman_Code.txt 创建失败!\n");return;}/* 将内存里的东西写入文件 */for (i = 0; i < n; i++){fprintf(fp, "%d ", ht[i].data);for (k = hcd[i].start; k <= n; k++){fprintf(fp, "%c", hcd[i].cd[k]);}if (i < n - 1) fprintf(fp, "\n");}/* 关闭文件指针 */fclose(fp);printf("代码表文件 Huffman_Code.txt 生成成功!\n");
}/* 打印哈夫曼编码到屏幕 */
void PrintHuffmanCode(int n)
{int i, k;printf("ASCII \t Char \t HuffmanCode\n");for (i = 0; i < n; i++){printf("%d \t \"%c\" \t ", ht[i].data, ht[i].data);for (k = hcd[i].start; k <= n; k++){printf("%c", hcd[i].cd[k]);}printf("\n");}
}/* 构造哈夫曼树 */
void CreateHT(int n)
{int i, k ,lmin, rmin;int min1, min2;/* 一共有2n-1个节点 */for (i = n; i < 2 * n - 1; i++){/*lmin和rmin为最小权重的两个节点置*/min1 = min2 = 0x7FFFFFFF;lmin = rmin = -1;for (k = 0; k <= i - 1; k++){/*只在尚未构造二叉树的节点中查找*/if (ht[k].parent == -1){if (ht[k].weight < min1){min2 = min1;rmin = lmin;min1 = ht[k].weight;lmin = k;}else if (ht[k].weight < min2){min2 = ht[k].weight;rmin = k;}}}/* 修改2个小权重节点的双亲 */ht[lmin].parent = i;ht[rmin].parent = i;/* 修改双亲的权重 */ht[i].weight = ht[lmin].weight + ht[rmin].weight;/* 修改双亲的孩子 */ht[i].lchild = lmin;ht[i].rchild = rmin;}
}/* 得到哈夫曼编码 */
void CreateHCode(int n)
{int i, f, c;Code hc;/* 根据哈夫曼树求哈夫曼编码 */for (i = 0; i < n; i++){hc.start = n;c = i;f = ht[i].parent;/* 循序直到树根结点 */while (f != -1){/* 处理左孩子结点 */if (ht[f].lchild == c){hc.cd[hc.start--] = '0';}/* 处理右孩子结点 */else{hc.cd[hc.start--] = '1';}c = f;f = ht[f].parent;}/* start指向哈夫曼编码最开始字符 */hc.start++;hcd[i] = hc;}
}


 

功能包括从文件中读取文章,将文章转换为哈夫曼编码,将哈夫曼编码还原,就是那几个基本算法的实现啦。

为了方便查看,这里输出的哈夫曼编码是1byte的,其实真正应该将其变为1bit存储,这样才能达到压缩的目的。

 

这篇关于C程序实践 哈夫曼(Huffman)树代码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/999736

相关文章

springboot项目中整合高德地图的实践

《springboot项目中整合高德地图的实践》:本文主要介绍springboot项目中整合高德地图的实践,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一:高德开放平台的使用二:创建数据库(我是用的是mysql)三:Springboot所需的依赖(根据你的需求再

SpringBoot3应用中集成和使用Spring Retry的实践记录

《SpringBoot3应用中集成和使用SpringRetry的实践记录》SpringRetry为SpringBoot3提供重试机制,支持注解和编程式两种方式,可配置重试策略与监听器,适用于临时性故... 目录1. 简介2. 环境准备3. 使用方式3.1 注解方式 基础使用自定义重试策略失败恢复机制注意事项

MySQL MCP 服务器安装配置最佳实践

《MySQLMCP服务器安装配置最佳实践》本文介绍MySQLMCP服务器的安装配置方法,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下... 目录mysql MCP 服务器安装配置指南简介功能特点安装方法数据库配置使用MCP Inspector进行调试开发指

SQLite3命令行工具最佳实践指南

《SQLite3命令行工具最佳实践指南》SQLite3是轻量级嵌入式数据库,无需服务器支持,具备ACID事务与跨平台特性,适用于小型项目和学习,sqlite3.exe作为命令行工具,支持SQL执行、数... 目录1. SQLite3简介和特点2. sqlite3.exe使用概述2.1 sqlite3.exe

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

SQL中JOIN操作的条件使用总结与实践

《SQL中JOIN操作的条件使用总结与实践》在SQL查询中,JOIN操作是多表关联的核心工具,本文将从原理,场景和最佳实践三个方面总结JOIN条件的使用规则,希望可以帮助开发者精准控制查询逻辑... 目录一、ON与WHERE的本质区别二、场景化条件使用规则三、最佳实践建议1.优先使用ON条件2.WHERE用

Springboot整合Redis主从实践

《Springboot整合Redis主从实践》:本文主要介绍Springboot整合Redis主从的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言原配置现配置测试LettuceConnectionFactory.setShareNativeConnect

Java中Map.Entry()含义及方法使用代码

《Java中Map.Entry()含义及方法使用代码》:本文主要介绍Java中Map.Entry()含义及方法使用的相关资料,Map.Entry是Java中Map的静态内部接口,用于表示键值对,其... 目录前言 Map.Entry作用核心方法常见使用场景1. 遍历 Map 的所有键值对2. 直接修改 Ma

python编写朋克风格的天气查询程序

《python编写朋克风格的天气查询程序》这篇文章主要为大家详细介绍了一个基于Python的桌面应用程序,使用了tkinter库来创建图形用户界面并通过requests库调用Open-MeteoAPI... 目录工具介绍工具使用说明python脚本内容如何运行脚本工具介绍这个天气查询工具是一个基于 Pyt

Ubuntu设置程序开机自启动的操作步骤

《Ubuntu设置程序开机自启动的操作步骤》在部署程序到边缘端时,我们总希望可以通电即启动我们写好的程序,本篇博客用以记录如何在ubuntu开机执行某条命令或者某个可执行程序,需要的朋友可以参考下... 目录1、概述2、图形界面设置3、设置为Systemd服务1、概述测试环境:Ubuntu22.04 带图