服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - 基于C语言利用哈夫曼树实现文件压缩的问题

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

2021-12-10 15:09Small Program C/C++

哈夫曼编码是一种编码方式,又称“霍夫曼编码”,其是可变字长的编码(VCL)的一种,这篇文章主要介绍了基于C语言利用哈夫曼树实现文件压缩,需要的朋友可以参考下

一、哈夫曼树

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

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

二、哈夫曼编码

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

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

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

2.1 如何得到哈夫曼编码

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

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

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

A:00        B:01        C:1

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

3.1 基本实现流程

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

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

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

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

3.3 读取,统计字符

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

?
1
2
3
4
5
6
7
8
9
10
11
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 构造哈夫曼树

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

?
1
2
3
4
5
6
7
8
9
10
CreateHT(ht,node);
       char strarr[256][256];
       int aa,bb;
       for(aa=0; aa<256;aa++)
           for(bb=0;bb<256;bb++)
               strarr[aa][bb]=-1;
       
       for(k = 0;k < node;k++){
           huffmanCode(ht,k,strarr[k]);
       }
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void CreateHT(HTNode *ht, int n){
    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 < i; j++){
            if(ht[j].parent == -1){
                if(ht[j].weight <lnode){
                    rnode = lnode;
                    n2 =n1;
                    lnode = ht[j].weight;
                    n1 = j;
                } else if(ht[j].weight < rnode){
                    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..

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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 < lengthOfKey; 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]);
            strcpy(oldstr, tmp);
            i += lengthOfRep - 1;
            oldstrLen = strlen(oldstr);
        }
    }
}

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

3.7 进制转换

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

3.7.1 进制转换方法

?
1
2
3
4
5
6
7
8
int retTen(char str[]){
    int ten = 0;
    int t = 0;
    for(t = 0;t < strlen(str);t++){
        ten += (str[t]-'0') * pow(2,strlen(str) - t - 1);
    }
    return ten;
}

3.7.2 实现效果

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

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

3.8 计算压缩率

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

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

?
1
2
3
4
5
6
int oldFileSize=getFileSize(path);
int newFileSize=getFileSize(Gopath);
        
printf("\n");
printf("压缩成功!,文件已压缩至%s\n",Gopath);
printf("该文件压缩率为:%.2lf\n",(double)newFileSize/(double)oldFileSize);

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

到此这篇关于基于C语言利用哈夫曼树实现文件压缩的文章就介绍到这了,更多相关C语言实现文件压缩内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/qq_49750651/article/details/118439285

延伸 · 阅读

精彩推荐
  • C/C++c/c++内存分配大小实例讲解

    c/c++内存分配大小实例讲解

    在本篇文章里小编给大家整理了一篇关于c/c++内存分配大小实例讲解内容,有需要的朋友们可以跟着学习参考下。...

    jihite5172022-02-22
  • C/C++关于C语言中E-R图的详解

    关于C语言中E-R图的详解

    今天小编就为大家分享一篇关于关于C语言中E-R图的详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看...

    Struggler095962021-07-12
  • C/C++OpenCV实现拼接图像的简单方法

    OpenCV实现拼接图像的简单方法

    这篇文章主要为大家详细介绍了OpenCV实现拼接图像的简单方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    iteye_183805102021-07-29
  • C/C++使用C++制作简单的web服务器(续)

    使用C++制作简单的web服务器(续)

    本文承接上文《使用C++制作简单的web服务器》,把web服务器做的功能稍微强大些,主要增加的功能是从文件中读取网页并返回给客户端,而不是把网页代码...

    C++教程网5492021-02-22
  • C/C++深入C++拷贝构造函数的总结详解

    深入C++拷贝构造函数的总结详解

    本篇文章是对C++中拷贝构造函数进行了总结与介绍。需要的朋友参考下...

    C++教程网5182020-11-30
  • C/C++c/c++实现获取域名的IP地址

    c/c++实现获取域名的IP地址

    本文给大家汇总介绍了使用c/c++实现获取域名的IP地址的几种方法以及这些方法的核心函数gethostbyname的详细用法,非常的实用,有需要的小伙伴可以参考下...

    C++教程网10262021-03-16
  • C/C++C语言实现双人五子棋游戏

    C语言实现双人五子棋游戏

    这篇文章主要为大家详细介绍了C语言实现双人五子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    两片空白7312021-11-12
  • C/C++C语言main函数的三种形式实例详解

    C语言main函数的三种形式实例详解

    这篇文章主要介绍了 C语言main函数的三种形式实例详解的相关资料,需要的朋友可以参考下...

    ieearth6912021-05-16