热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

基于C语言利用哈夫曼树实现文件压缩

原标题:基于C语言利用哈夫曼树实现文件压缩一、哈夫曼树具有n个权值的n个叶子结点,构造出一个二叉树

原标题:基于C语言利用哈夫曼树实现文件压缩

一、哈夫曼树

具有n个权值的n个叶子结点,构造出一个二叉树,使得该树的带权路径长度(WPL)最小,则称此二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。

注意:哈夫曼树是带权路径长度最短的树,且权值越大的叶子结点离根结点越近。

二、哈夫曼编码

哈夫曼编码是一种编码方式,又称“霍夫曼编码”,其是可变字长的编码(VCL)的一种,是由霍夫曼于1952年提出的一种编码方式,有时被称为最佳编码,一般称为Huffman编码

那么我们为什么要使用哈夫曼编码进行压缩?

首先原因在于,传统压缩方式中,字www.yii666.com符的编码是以等字长的方式进行压缩,相比于哈夫曼编码的可变字长而言压缩率会降低。其次,传统方式中可能会出现某些字符的编码相同,存在二义性,相比于哈夫曼编码的唯一性。可以大大提高正确性。

2.1如何得到哈夫曼编码

通过已经构造的哈夫曼树,结点左分支记为二进制数“0”,结点右分支记为二进制数“1”。从根结点向下到该叶子结点路途经过的数字拼接成为的编码即为该字符的哈夫曼编码。现通过以下图例进行演示。

此时各字符对应的哈夫曼编码可表示为:

A:00 B:01 C:1

三、哈夫曼树实现文件压缩基本步骤

3.1 基本实现流程

3.2使用文件输入流读取需压缩的文件,并判断该文件是否存在

存在后执行接下来的步骤,不存在提示用户,效果图如下

3.3 读取,统计字符

用户输入正确文件路径且存在时使用文件输入流读取文件,将文件放于一个字符数组中(注意字符数组开辟空间应足够大)。统计出现的字符及其出现的次数。

char ch;
while(feof(fp) == 0){
fscanf(fp,"%c",&ch);
str[ch]++;
}
printf("\n");
for(i = 0; i <1024; i++){
if(str[i] != 0){
count[n++] = i;
}
}

3.4 构造哈夫曼树

注:由于后续会使用此哈夫曼编码,为了方便获取,这里将求出的哈夫曼编码放置于一个二维数组中。

CreateHT(ht,node);
char strarr[256][www.yii666.com256];
int aa,bb;
for(aa=0; aa<256;aa++)
for(bb=0;bb<256;bb++)
strarr[aa][bb]=-1;

for(k = 0;k huffmanCode(ht,k,strarr[k]);
}

void CreateHT(HTNode *ht, int n){文章来源地址48717.html
int i, j, lnode, rnode n1, n2;
for(i = n; i <2*n-1; i++){
lnode = 65432; rnode = lnode;
n1 = 0; n2 = 0;
for(j = 0; j if(ht[j].parent == -1){
if(ht[j].weight rnode = lnode;
n2 =n1;
lnode = ht[j].weight;
n1 = j;
} else if(ht[j].weight rnode = ht[j].weight;
n2 = j;
}
}
}
ht[n1].parent = i;
ht[n2].parent = i;

ht[i].weight = lnode+rnode;
ht[i].parent = -1;
ht[i].lchild = n1;
ht[i].rchild = n2;
}
}

3.5 根据构造哈夫曼树得到哈夫曼编码

此时我们使用3.3中统计的字符作为叶子结点,其出现次数作为权值,构造哈夫曼树求出哈夫曼编码。下面以此段英文为例,得到每个字符对应哈夫曼编码。

You can take away our money,house,car,or even our clothes and we can surive.But if our health was taken away,we would surely die.That is why we always try to eat in a healthy way and excise regularly..

3.6 替换字符为其哈夫曼编码

用户输入压缩至的文件路径,将替换好的0 1数字字符数组写入该文件。由于C语言没有基于字符串的操做,所以我们替换时只能通过对字符数组进行操作,涉及到了被替换字符串长度替换字符串长度的问题,以及字符数组的长度是否充足。由于此次替换被替换字符串只是一个字符,且字符数组开辟空间足够大。所以只考虑替换字符串长度,即字符对应哈夫曼编码的长度,在这里使用一个方法来进行替换。

void replace(char oldstr[], char key[], char rep[]){
int oldstrLen, lengthOfKey, lengthOfRep, i, j , flag;
char tmp[1000];
oldstrLen = strlen(oldstr);
lengthOfKey = strlen(key);
lengthOfRep = strlen(rep);
for( i = 0; i <= oldstrLen - lengthOfKey; i++){
flag = 1;
for(j = 0; j if(oldstr[i + j] != key[j]){
flag = 0;
break;
}
}
if(flag){
strcpy(tmp, oldstr);
strcpy(&tmp[i], rep);
strcpy(&tmp[i + lengthOfRep], &oldstr[i + lengthOfKey文章来源站点https://www.yii666.com/]);
strcpy(oldstr, tmp);
i += lengthOfRep - 1;
oldstrLen = strlen(oldstr);
}
}
}

替换完成后的字符数组使用输出流写入用户输入文件路径。

3.7 进制转换

将文件中每八位二进制数转换为十进制数,再转换为其对应的ASCII码值,最后不足八位的二进制数以0补齐,实现文件压缩。

3.7.1 进制转换方法

int ret文章来源地址48717.htmlTen(char str[]){
int ten = 0;
int t = 0;
for(t = 0;t ten += (str[t]-'0') * pow(2,strlen(str) - t - 1);
}
return ten;
}

3.7.2 实现效果

3.8 计算压缩率

最后为验证是否实现压缩,可通过计算文件压缩率来验证。其中,压缩率=原文件字节大小/压缩后文件大小。

int oldFileSize=getFileSize(path);
int newFileSize=getFileSize(Gopath);

printf("\n");
printf("压缩成功!,文件已压缩至%s\n",Gopath);
printf("该文件压缩率为:%.2lf\n",(double)newFileSize/(double)oldFileSize);

注:注意计算压缩率时的类型转换

String a = "135";
String b = "1097";
String c = "431";
System.out.println("源码+扣扣"+a+b+c);

来源于:基于C语言利用哈夫曼树实现文件压缩


推荐阅读
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • 电话号码的字母组合解题思路和代码示例
    本文介绍了力扣题目《电话号码的字母组合》的解题思路和代码示例。通过使用哈希表和递归求解的方法,可以将给定的电话号码转换为对应的字母组合。详细的解题思路和代码示例可以帮助读者更好地理解和实现该题目。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文详细介绍了PHP中与URL处理相关的三个函数:http_build_query、parse_str和查询字符串的解析。通过示例和语法说明,讲解了这些函数的使用方法和作用,帮助读者更好地理解和应用。 ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文介绍了Linux Shell中括号和整数扩展的使用方法,包括命令组、命令替换、初始化数组以及算术表达式和逻辑判断的相关内容。括号中的命令将会在新开的子shell中顺序执行,括号中的变量不能被脚本余下的部分使用。命令替换可以用于将命令的标准输出作为另一个命令的输入。括号中的运算符和表达式符合C语言运算规则,可以用在整数扩展中进行算术计算和逻辑判断。 ... [详细]
  • 简述在某个项目中需要分析PHP代码,分离出对应的函数调用(以及源代码对应的位置)。虽然这使用正则也可以实现,但无论从效率还是代码复杂度方面考虑ÿ ... [详细]
author-avatar
村医医治世界经济
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有