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中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

使用C#代码在PDF文档中添加、删除和替换图片

《使用C#代码在PDF文档中添加、删除和替换图片》在当今数字化文档处理场景中,动态操作PDF文档中的图像已成为企业级应用开发的核心需求之一,本文将介绍如何在.NET平台使用C#代码在PDF文档中添加、... 目录引言用C#添加图片到PDF文档用C#删除PDF文档中的图片用C#替换PDF文档中的图片引言在当

C#使用SQLite进行大数据量高效处理的代码示例

《C#使用SQLite进行大数据量高效处理的代码示例》在软件开发中,高效处理大数据量是一个常见且具有挑战性的任务,SQLite因其零配置、嵌入式、跨平台的特性,成为许多开发者的首选数据库,本文将深入探... 目录前言准备工作数据实体核心技术批量插入:从乌龟到猎豹的蜕变分页查询:加载百万数据异步处理:拒绝界面

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

Spring Boot 配置文件之类型、加载顺序与最佳实践记录

《SpringBoot配置文件之类型、加载顺序与最佳实践记录》SpringBoot的配置文件是灵活且强大的工具,通过合理的配置管理,可以让应用开发和部署更加高效,无论是简单的属性配置,还是复杂... 目录Spring Boot 配置文件详解一、Spring Boot 配置文件类型1.1 applicatio

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu

java之Objects.nonNull用法代码解读

《java之Objects.nonNull用法代码解读》:本文主要介绍java之Objects.nonNull用法代码,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录Java之Objects.nonwww.chinasem.cnNull用法代码Objects.nonN

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

tomcat多实例部署的项目实践

《tomcat多实例部署的项目实践》Tomcat多实例是指在一台设备上运行多个Tomcat服务,这些Tomcat相互独立,本文主要介绍了tomcat多实例部署的项目实践,具有一定的参考价值,感兴趣的可... 目录1.创建项目目录,测试文China编程件2js.创建实例的安装目录3.准备实例的配置文件4.编辑实例的

python+opencv处理颜色之将目标颜色转换实例代码

《python+opencv处理颜色之将目标颜色转换实例代码》OpenCV是一个的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上,:本文主要介绍python+ope... 目录下面是代码+ 效果 + 解释转HSV: 关于颜色总是要转HSV的掩膜再标注总结 目标:将红色的部分滤