哈夫曼压缩与解压缩的实现

  • 开始之前,务必要看!看了能更好的理解代码
  • 一、整体的布局
  • 二、模块功能实现
    • 1、压缩
    • 2、解压缩
  • 三、尾记-主函数的详细介绍

开始之前,务必要看!看了能更好的理解代码

为了伙伴们更好的理解我们这个代码的实现,笔者先手动计算一个压缩过程,这样我们就能对整体的代码有一个了解了:
这一部分请真心想要做出哈夫曼压缩解压缩的伙伴们一定认真看,因为这里的逻辑就是代码的逻辑:
假设我们有一个字符串是:acefkmffmkfafkaffakaeef

那么它的哈夫曼树如图:

之后,我们进行计算:

这里我们说存入参数,其实就是存入了哈夫曼编码,实际上压缩是压缩了,但是参数比较多,就导致压缩后的文件反而比原文件大。

一、整体的布局

我们已经对整体的逻辑实现有了一个了解,现在就来看看具体的代码吧:

我们想要做到功能分模块,也就是我可以自主选择是压缩还是解压缩,并且查看情况,那么我们就把业务逻辑分离:

那么我们首先看看最简单的头文件huffman.h书写了什么东西吧!

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include<time.h>
#include<Windows.h>
struct HuffmanNode
{int letter;                          //保存字符的映射long count;                   //文件中该字符出现的次数long parent, lchild, rchild;        //构建二叉树所需的数据char bits[256];               //对应的哈夫曼编码
};struct HuffmanNode TreeNode[512], tmp, temp;  //节点树,TreeNode.count用来记录数据出现的次数
//函数compress(),读取文件内容并加以压缩,将压缩内容写入另一个文档
int compress(const char* filename, const char* outputfile);
//函数:uncompress(),作用:解压缩文件,并将解压后的内容写入新文件
int uncompress(const char* filename, const char* outputfile);

头文件主要就写了一些定义,并包含了其他可能需要的头文件。

现在来看看test.c文件
为了我们更好的互动,在测试文件中书写一个菜单,供选择,那么这个代码很简单:

#include"huffman.h"//注意头文件的包含
void menu()
{printf("\n1,压缩文件\n");printf("2,解压缩文件\n");printf("3,读取解压缩文件\n");printf("4,查看哈夫曼编码\n");printf("输入'q'退出程序\n");printf("请选择需要的操作:\n");
}

至于功能的实现,我们自然还是选择swtich语句,这里我们就需要考虑可能要写的功能了,比如,压缩文件,我们书写一个compress()函数,解压缩文件,我们书写一个uncompress()函数,读取文件的话,其实不需要再写函数,可以直接在uncompree()函数里实现解压缩文件的读取,而查看哈夫曼代码,我们既可以在编写哈夫曼树的时候去书写,也可以在解压缩的时候书写。

所以,简单的讲,我们只需要书写两个模块,就可以实现我们想要的功能,那么我们先看看逻辑主函数里都写了什么吧!

当然,这里的主函数会在尾记的时候详细的说一遍,这里可以选择不去理解。

void main()
{clock_t begin, end;double cost;FILE* fp;char ch, temparray[30];int ret1, ret2;int choice, count = 0, n;long f;memset(&TreeNode, 0, sizeof(TreeNode));memset(&tmp, 0, sizeof(tmp));menu();while (scanf("%d", &choice) == 1){   system("cls");switch (choice){case 1:ret1 = compress("data.txt", "data.zip.txt");menu();break;case 2://开始记录begin = clock();ret2 = uncompress("data.zip.txt", "data.unzip.txt");//结束记录end = clock();cost = (double)(end - begin) / CLOCKS_PER_SEC;printf("解压缩耗时: %lf secs\n", cost);printf("压缩比率是%.3lf%%\n", ((double)ret1 / ret2) * 100);menu();break;case 3:printf("读取解压后的文件:\n");if ((fp = fopen("data.unzip.txt", "rt")) == NULL) {printf("读取失败!\n");exit(1);}ch = fgetc(fp);while (ch != EOF) {putchar(ch);ch = fgetc(fp);}fclose(fp);menu();break;case 4:if ((fp = fopen("data.zip.txt", "rb")) == NULL){printf("读取失败!\n");exit(1);}fseek(fp, 4, SEEK_SET);fread(&f, sizeof(long), 1, fp);fseek(fp, f, SEEK_SET);fread(&n, sizeof(long), 1, fp);//读取字符种类总数for (int i = 0; i < n; i++){printf("字符:%-5c频数:%-6ld哈夫曼编码:%-20s", TreeNode[i].letter, TreeNode[i].count, TreeNode[i].bits);count++;if (count % 4 == 0)printf("\n");}menu();break;case 6:printf("欢迎再次使用!\n");default:break;}}
}

我们每次实现一个功能,再去选择另一个功能,就清理一下屏幕,所以这里书写了一个system("cls"),以便屏幕看着整洁一点。当然,可以根据个人的需要去更改。

由于我们希望计算压缩比率,那么我们书写模块的时候,还需要注意需要返回字节数。也就是书写一个有返回值的函数。

现在要看懂这些代码还是不行的,因为这里的功能的选择依赖于书写的模块的内容。所以我们还得继续看看模块都写了什么,才能理解这个main()函数的含义(并且在尾记里还会再介绍的,保证让每个人能有所收获)。放心,笔者会一一解释所有的可能的难点。

二、模块功能实现

1、压缩

压缩的功能就是读取原文件,进行压缩并写入新文件。这里几乎每一行代码我都给了注释,小伙伴们应该都可以看懂的,所以只挑几个必要的说一说了。

压缩文件的难点就在于写入压缩文件,也就是说,我们需要写入什么东西?因为SEEK_SET可以快速找到文件开头,这里我们在文件开头就写入原文件字节数和压缩文件字节数,为了防止丢失数据(如果不写在开头,就读不到这些数据)

之后我们就存入压缩文件的容器(char类型,个数也就是存储的压缩文件字节数,所以现在理解为什么要存储原文件长和压缩文件长了吗?是为了不多读取,也不少读取

然后我们在末尾再存入自己编写的哈夫曼编码(实际上更像一个自己写的ASCII编码表),这些参数的个数我们也需要记录,不然不好读取,也就是记录一共统计了多少个字符。

#include"huffman.h"//务必注意包含头文件
int compress(const char* filename, const char* outputfile)
{char temparray[256];unsigned char c;long i, j, m, n, f;long lowest, pt, filelength;FILE* inputfilep, * outputfilep;int k, q;inputfilep = fopen(filename, "rb");//打开文件夹的原始文件if (inputfilep == NULL){printf("打开文件失败\n");return 0;}outputfilep = fopen(outputfile, "wb");//打开压缩后存储信息的文件,如果没有就创建if (outputfilep == NULL){printf("打开文件失败\n");return 0;}filelength = 0;while (!feof(inputfilep))//功能是检测流上的文件结束符,如果文件结束,则返回非0值,否则返回0{fread(&c, 1, 1, inputfilep);//从给定文件inputfilep 读取数据到cTreeNode[c].count++;//读文件,统计每个字符出现次数,并且使用是ASCII码filelength++;//记录文件的字符总数}filelength--;//去掉结束符TreeNode[c].count--;for (i = 0; i < 512; i++) //huffman算法中初始节点的设置{if (TreeNode[i].count != 0)//512个不一定都用了TreeNode[i].letter = i;//映射成ASCII码else    //赋值-1是为了避免哈夫曼编码时使用0出现冲突TreeNode[i].letter = -1;TreeNode[i].parent = -1;TreeNode[i].lchild = TreeNode[i].rchild = -1;}//将节点按出现次数排序(选择排序)for (i = 0; i < 256; i++)//每次都向后完成一次{k = i;//k用来记录变化的位置for (q = i + 1; q < 256; q++)//每次都在没有排序的数里进行循环if (TreeNode[k].count < TreeNode[q].count)k = q;//挑没排序的数里数据最大的temp = TreeNode[i];//用t来暂时存储数据(为了与后面的小数据交换)TreeNode[i] = TreeNode[k];//把数据最大的赋值TreeNode[k] = temp;//把暂存的数据赋值给原来值大的,实现交换}for (i = 0; i < 256; i++)//统计不同字符的数量{if (TreeNode[i].count == 0)break;}//统计出i的数值,以便下面使用n = i;m = 2 * n - 1;//m是总结点数for (i = n; i < m; i++)//使用空结点{lowest = 999999999;//保证后面的if一定开始执行for (j = 0; j < i; j++){if (TreeNode[j].parent != -1) continue;if (lowest > TreeNode[j].count){lowest = TreeNode[j].count;pt = j;}}TreeNode[i].count = TreeNode[pt].count;TreeNode[pt].parent = i;TreeNode[i].lchild = pt;lowest = 999999999;for (j = 0; j < i; j++){if (TreeNode[j].parent != -1) continue;if (lowest > TreeNode[j].count){lowest = TreeNode[j].count;pt = j;}}TreeNode[i].count += TreeNode[pt].count;TreeNode[i].rchild = pt;TreeNode[pt].parent = i;}for (i = 0; i < n; i++)//设置字符的编码{f = i;//从构造数的第一个结点开始,依次对结点进行编排TreeNode[i].bits[0] = 0;//初始化while (TreeNode[f].parent != -1)//只要有父节点,就进行编排,第一次没有父节点就是根节点{j = f;f = TreeNode[f].parent;if (TreeNode[f].lchild == j)//左孩子编0{j = strlen(TreeNode[i].bits);memmove(TreeNode[i].bits + 1, TreeNode[i].bits, j + 1);TreeNode[i].bits[0] = '0';}else//右孩子编1{j = strlen(TreeNode[i].bits);memmove(TreeNode[i].bits + 1, TreeNode[i].bits, j + 1);TreeNode[i].bits[0] = '1';}}}//下面的就是读原文件的每一个字符,按照设置好的编码替换文件中的字符fseek(inputfilep, 0, SEEK_SET);    //将指针定在文件起始位置,没有任何偏移fseek(outputfilep, 8, SEEK_SET);   //以8位二进制数为单位,每次移动偏移进行读取temparray[0] = 0;pt = 8;//后面写入了一共八字节的filelength和ptprintf("读取将要压缩的文件:%s\n", filename);printf("当前文件有:%d字符\n", filelength);//压缩文件while (!feof(inputfilep)){c = fgetc(inputfilep);//获取下一个字符(一个无符号字符)for (i = 0; i < n; i++)//n是字符种类总数{if (c == TreeNode[i].letter) //如果读取的字符与我们字符种类映射的ACSCII某一个对应break;}strcat(temparray, TreeNode[i].bits);//那么就把此字符种类的编码追加给temparray来暂存j = strlen(temparray);//j用来暂存初始编码总长c = 0;//二进制是00000000if (j >= 8)//只要存的编码位数大于8,就执行操作写入文件{for (i = 0; i < 8; i++)//按照八位二进制数转化写入文件一次进行压缩{if (temparray[i] == '1') {c = c << 1;c = c + 1;}//c的二进制数左移并加1else c = c << 1;//c的二进制数字左移}//实现二进制的读取和记录fwrite(&c, sizeof(char), 1, outputfilep);//printf("%s",temparray);//temparray数组存储的是char保存的二进制内容pt++;//pt使用的初始值是8,用于记录字节数strcpy(temparray, temparray + 8);//temparray的值重新覆盖}}if (j > 0)//当剩余字符数量少于8个时{strcat(temparray, "00000000");for (i = 0; i < 8; i++){if (temparray[i] == '1'){c = c << 1;c += 1;//位运算}else c = c << 1;//对不足的位数进行补零}fwrite(&c, 1, 1, outputfilep);pt++;}fseek(outputfilep, 0, SEEK_SET);//偏移量为零,重新找到开头位置写入参数//使用outputfilep指针来确定文件的开头,将编码信息写入存储文件fwrite(&filelength, 4, 1, outputfilep);//1是写入的元素大小,sizeof(filelength)是需要写入的长度。这些内容写入ouputfilepfwrite(&pt, 4, 1, outputfilep);//写入四字节fseek(outputfilep, pt, SEEK_SET);//从给定的开头位置,pt大小(压缩之后的位置),在outputfile里读取fwrite(&n, 4, 1, outputfilep);//写一个四字节的数据,要注意pt的累加//以上是写入压缩的各类参数:字符种类总数,字符总数for (i = 0; i < n; i++){tmp = TreeNode[i];fwrite(&(TreeNode[i].letter), 1, 1, outputfilep);//写入各类字符pt++;c = strlen(TreeNode[i].bits);//映射fwrite(&c, 1, 1, outputfilep);pt++;j = strlen(TreeNode[i].bits);if (j % 8 != 0)//当位数不满8时,对该数进行补零操作(为了一字节八位数的保存){for (f = j % 8; f < 8; f++)strcat(TreeNode[i].bits, "0");}while (TreeNode[i].bits[0] != 0){c = 0;//赋值00000000for (j = 0; j < 8; j++){if (TreeNode[i].bits[j] == '1'){c = c << 1;c += 1;//进行位运算}else c = c << 1;//不是1就补0}strcpy(TreeNode[i].bits, TreeNode[i].bits + 8);fwrite(&c, 1, 1, outputfilep);//将所得的编码信息写入文件pt++;}//以上写入各字符种类哈夫曼编码的数据TreeNode[i] = tmp;}fclose(inputfilep);fclose(outputfilep);//关闭文件printf("\n压缩后文件为:%s\n", outputfile);printf("压缩后文件有:%d字符\n", pt + 4);//之前写入了一个四字节的n,所以需要加4return pt + 4;//返回压缩成功信息
}

至于位运算,注释给的也很详细,哈夫曼树的编写,就读者自己看看书喽,我们日后再写一篇文章讲一讲哈夫曼树的编写。不然这篇文章就太长啦!

2、解压缩

至于解压缩,也就是读取压缩文件,并把读取结果写入新文件,所以压缩的时候,我们主要使用fseek和fwrite,解压缩的时候,我们就主要使用fseek和fread了。

同样的,几乎每一行代码都给了注释,认真看一看都能看懂。

现在就挑几个不好理解的说一说:

读取的时候,我们需要注意先读取原文件长和压缩文件长,这样我们才能让程序知道,它在读压缩文件的时候应该读多少个,不能读多了,读多了就读到参数了(就是后面存储的哈夫曼编码的数据,那就读多了)

之后是读取参数的数据(获取解压缩的数据,不然没有编码也解压不了)

最后一步就是利用读取到的参数进行转译了,这一步就是写入新文件的过程,还是需要使用fwrite函数的。

至此,我们的哈夫曼解压缩也就实现了。

int uncompress(const char* filename, const char* outputfile)
{char temparray[256], bx[256];unsigned char c;long i, j, m, n, k, f, p, l;long filelength;int len = 0;FILE* inputfilep, * outputfilep;char cname[512] = { 0 };inputfilep = fopen(filename, "rb");//打开压缩的文件if (inputfilep == NULL){printf("文件打开失败!");return 0;//若打开失败,则输出错误信息}outputfilep = fopen(outputfile, "wb");//打开新文件,用于解压缩if (outputfilep == NULL){return 0;}fseek(inputfilep, 0, SEEK_END);//定下指针位置len = ftell(inputfilep);//记录的是inputfilep的位置,也就是字节数fseek(inputfilep, 0, SEEK_SET);printf("将要读取解压的文件:%s\n", filename);printf("当前文件有:%d字符\n", len);fread(&filelength, sizeof(long), 1, inputfilep);//读取原文件长fread(&f, sizeof(long), 1, inputfilep);//f读取的是需要压缩文件的长度,不包括参数fseek(inputfilep, f, SEEK_SET);//从文件的f位置后开始读fread(&n, sizeof(long), 1, inputfilep);//读取字符种类总数for (i = 0; i < n; i++)//读取压缩文件内容并转换成二进制码{fread(&TreeNode[i].letter, 1, 1, inputfilep);//读取字符(ASCII码)fread(&c, 1, 1, inputfilep);//读取字符编码的数据strlen(TreeNode[i].bits))p = (long)c;//读的是编码的长度,编码的长度与count反相关TreeNode[i].count = p;TreeNode[i].bits[0] = 0;//赋初值if (p % 8 > 0) //判断字节m = p / 8 + 1;else m = p / 8;for (j = 0; j < m; j++){fread(&c, 1, 1, inputfilep);//此步读取的是单个字符类的二进制码f = c;_itoa(f, temparray, 2);//将f的值转为2进制存入temparray,此时temparray存的是二进制f = strlen(temparray);for (l = 8; l > f; l--){strcat(TreeNode[i].bits, "0");//位数不足,执行补零操作}strcat(TreeNode[i].bits, temparray);}TreeNode[i].bits[p] = 0;}//接受解压所需要的参数,读取必要的文件for (i = 0; i < n; i++)//每次都向后完成一次{k = i;//k用来记录变化的位置for (j = i + 1; j < n; j++)//每次都在没有排序的组里进行循环if (strlen(TreeNode[k].bits) > strlen(TreeNode[j].bits))//长度最小的是出现次数最多的k = j;//取短的tmp = TreeNode[i];//用t来暂时存储数据TreeNode[i] = TreeNode[k];//k是略长的值,换到后面TreeNode[k] = tmp;//实现交换}//排序的目的是快速找到读取解压对应的字母p = strlen(TreeNode[n - 1].bits);//p取了一个长度最长的fseek(inputfilep, 8, SEEK_SET);//前八位存了两个四字节数据m = 0;bx[0] = 0;while (1){while (strlen(bx) < (unsigned int)p){fread(&c, 1, 1, inputfilep);//读取压缩的文件f = c;//f是一个数,转换十进制再转换二进制丢失了0_itoa(f, temparray, 2);//f转换成二进制暂存入temparrayf = strlen(temparray);for (l = 8; l > f; l--){strcat(bx, "0");}//如果不足八位,补零strcat(bx, temparray);}for (i = 0; i < n; i++){if (memcmp(TreeNode[i].bits, bx, TreeNode[i].count) == 0)break;//比较字节数是为了保证数组保存的二进制数字相同}strcpy(bx, bx + TreeNode[i].count);//进行赋值覆盖c = TreeNode[i].letter;//写入ASCII码fwrite(&c, 1, 1, outputfilep);//写入解码的文件m++;if (m == filelength)//限定写入只写到原文件的内容,再往后就是存储的参数break;}//读取压缩文件内容,解压缩的过程fclose(inputfilep);fclose(outputfilep);printf("解压后文件为:%s\n", outputfile);printf("解压后文件有:%d字符\n", filelength);return filelength;//输出成功信息
}

把压缩的过程理解了,解压缩其实就没什么不能理解的了。

三、尾记-主函数的详细介绍

为什么写尾记呢?因为我们要在这个地方再看一看主函数的功能实现,这样就能让读者们真正的了解这些代码的运行了。
初始化内存就没什么好说的,不操作的话,可能运行不起来

    memset(&TreeNode, 0, sizeof(TreeNode));memset(&tmp, 0, sizeof(tmp));

这个代码 while (scanf("%d", &choice) == 1)

 while (scanf("%d", &choice) == 1){......}

则实现了输入字母就退出,当然,我们也可以定向的作其他修改,看读者的需求了。
scanf函数的返回值是正确读取的个数,所以只要我们输入字母,就会退出循环,从而实现想要的功能
swtich语句的case1和case2没什么好讲的,就是基本的模块直接调用。
case3,我们是要实现读取解压缩的文件:

 case 3:printf("读取解压后的文件:\n");if ((fp = fopen("data.unzip.txt", "rt")) == NULL) {printf("读取失败!\n");exit(1);}ch = fgetc(fp);while (ch != EOF) {putchar(ch);ch = fgetc(fp);}fclose(fp);menu();break;

那么这里我们就需要打开文件,并且使用 end of file 结束标志。这一个读取还是很简单,不需要itoa转换二进制,因为解压缩的文件已经是字符文件。

case4,我们是要读取哈夫曼编码的一些数据,如图:

那么由于我们书写的文件里已经有参数的数据,我们直接找到压缩的文件,读取一下有多少个字符种类,然后用一个循环把结构体打印出来就可以了。

(当然,笔者认为自己使用的这种方法是一个笨方法,我们也可以直接定义一个全局变量,在压缩的时候就存储一下字符种类个数)

这里的找到文件的操作,需要使用SEEK_SET的一些知识,上面的代码已经都给出了使用的说明和注释。

 case 4:if ((fp = fopen("data.zip.txt", "rb")) == NULL){printf("读取失败!\n");exit(1);}fseek(fp, 4, SEEK_SET);fread(&f, sizeof(long), 1, fp);fseek(fp, f, SEEK_SET);fread(&n, sizeof(long), 1, fp);//读取字符种类总数for (int i = 0; i < n; i++){printf("字符:%-5c频数:%-6ld哈夫曼编码:%-20s", TreeNode[i].letter, TreeNode[i].count, TreeNode[i].bits);count++;if (count % 4 == 0)printf("\n");}menu();break;

那么,现在,我们要实现的功能就都已经书写了,如果有小伙伴说,我想看到二进制的数据,怎么才能看到呢?

二进制文件,我们是打不开的,看到的都是乱码,不过我们可以使用itoa函数外加一个辅助数组,把写入到压缩文件里的容器一个一个读出来,这样得到的也是一个可以被我们看到的二进制的一些数字(但注意,这不是二进制哦)。有兴趣的小伙伴可以自己实现一下。

今天的分享就到这里了,希望老铁们有所收获,我们下次再见。

C语言实现哈夫曼压缩与解压缩的实现以及读取哈夫曼编码 万文长书,绝对详细哦相关推荐

  1. 哈夫曼压缩(一)——英文文本

    本文主要介绍如何实现哈夫曼压缩以及提高哈夫曼压缩过程的读写速率,对于哈夫曼树的概念及其构造则没有介绍,感兴趣的朋友可以先百度一下了解相关知识. 一.哈夫曼压缩原理 哈夫曼压缩是一种无损的压缩算法,在压 ...

  2. c语言哈夫曼压缩文本,用哈夫曼压缩文件(C语言)

    用哈夫曼压缩文件(C语言) 用哈夫曼压缩文件(C语言) 2007-12-29 21:09:15| 分类: 编程 | 标签: |字号大中小 订阅 利用哈夫曼编码制作压缩软件,内容如下: #include ...

  3. [小项目]手把手教你C语言哈夫曼压缩/解压缩

    前言 这是大一写过的一个小项目,现在大三,重新实现了一下.这是原来的链接,可以看一下效果,思路和现在的一样. 扩展性.健壮性比原来更好,思路也更清晰了.当时只想花里胡哨,这次重心放在质量.功能上. 后 ...

  4. 【C语言-数据结构与算法】-哈夫曼压缩解压缩-终局-如何做一个自己独有的压缩软件

    哈夫曼压缩&解压缩 Ⅰ 前言 Ⅱ 需求分析&主函数带参的应用 A. 需求分析 B. 压缩部分 B. 解压缩部分 Ⅲ 哈夫曼压缩 A. 代码分析 B. 从文件中读取内容生成频度表 C. ...

  5. 【C语言->数据结构与算法】->哈夫曼压缩解压缩->第一阶段->哈夫曼编码解码的实现

    文章目录 Ⅰ 前言 Ⅱ 代码实现哈夫曼编码&解码 A. 构造哈夫曼树 a. 频度统计 b. 生成哈夫曼树 ① 初始化节点 ② 查找频度最小节点 ③ 哈夫曼树的构造 B. 哈夫曼编码 a. 得到 ...

  6. 数据结构编程实践(七)创建哈夫曼树、生成哈夫曼编码、完成图片的压缩与解压缩

    一.对图片的压缩与解压缩,涉及以下内容: 1.文件读写 2.创建Huffman树 3.生成Huffman编码 4.压缩图片文件 5 .  解压缩图片文件 二.将项目分成三个小任务,下一任务是在上一任务 ...

  7. 哈夫曼树实现文件的压缩与解压缩

    利用哈夫曼树实现文件的压缩与解压缩 压缩: 1.统计出文件中相同字符出现的次数 2.获取哈夫曼编码 次数作为权值构建哈夫曼树 3.重新编码,写回压缩文件 保存头文件: 源文件后缀 编码信息的行数 每个 ...

  8. 哈夫曼压缩和矩阵压缩存储

    对于数组的压缩存储,一维数组主要使用哈夫曼压缩,多维数组主要采用矩阵压缩的形式,对特殊矩阵和系数矩阵进行压缩. 哈夫曼压缩 哈夫曼压缩是由哈夫曼树推广而来的,是哈夫曼编码的重要应用.哈夫曼树 ─ 即最 ...

  9. c语言语言写压缩软件,哈弗曼压缩软件C语言代码.pdf

    哈弗曼压缩软件C语言代码 //========湖南理工学院====// //==========作者:余佳,尊重版权=====// //==========#include============ # ...

  10. 哈夫曼树(最优二叉树)、哈夫曼编码

    在此祝大家新年快乐,新的一年守住头发,不断进步! 哈夫曼树 一.哈夫曼树基本概念 二.哈夫曼树的构造算法 三.哈夫曼构造算法的实现 四.哈夫曼编码 五.哈夫曼编码的算法实现 一.哈夫曼树基本概念 (1 ...

最新文章

  1. Java调用ocx控件以及dll
  2. python长度分割文本_python 按照固定长度分割字符串的方法小结
  3. VTK:PolyData之ExtractOutsideSurface
  4. 字符串substring方法在jkd6,7,8中的差异
  5. java中XPATH操作xml,非常便捷
  6. JS判断文本框中只能输入数字和小数点
  7. 微信小程序js数组初始化_微信小程序 数组(增,删,改,查)等操作实例详解...
  8. Magento: 判断是否为手机浏览 Optimise Web's Mobile Detect Class for Magento
  9. 基于JAVA+SpringMVC+Mybatis+MYSQL的电影院订票系统
  10. FTP 文件上传跟下载
  11. 教程 ios 4 以上安装mobile terminal的最简单方法
  12. 怎么将PDF转换成jpg图片?免费方法了解一下
  13. Error:A JNI error has occurred,please check your installation and try again
  14. CENTOS 7 添加黑名单禁止IP访问服务器
  15. word导航栏 字体大小修改
  16. 制作android动态壁纸,使用视差滚动制作Android动态壁纸
  17. 摘自一个MILLION SONG DATASET里的一段读取基于HDF5文件格式的歌曲信息
  18. axios 之 post请求参数格式不正确得问题
  19. 电视剧《天道》观后感
  20. 机器学习中的优化算法介绍

热门文章

  1. Excel-VBA 快速上手(三、数组和字典)
  2. 【开发经验】quartz表结构说明(字段说明)
  3. CTF训练(密码学)——Atbash Cipher
  4. html微信公众平台登录界面,微信公众平台登录界面在哪里
  5. RN5T5611用于车载品的可编程电源管理IC
  6. 校园火灾项目结合Focus
  7. 运算放大器的简单介绍和运用
  8. oracle同义词不再有效,ORA-00980: 同义词转换不再有效
  9. 【★】选择好游戏认准这30个特质!
  10. mysql自增长id用完了,怎么办?