目录

  • 开发环境:
  • 代码:

开发环境:

DEV C++

代码:

#include<iostream>
#include<conio.h>
#include<cstring>
#include<vector>
#include<fstream>
#include<queue>
#include<ctime>
using namespace std;
long node[256];//用于存储ASCII码在文件中出现的频率
string m[256];//Huffman编码与ASCII匹配数组
long FileLength=0;//统计文件长度处理文件结尾字节匹配问题
/*
Huffman树节点的建立:
weight:节点的权重  code:该节点代表的源码,left和right:左右孩子
*/
struct Tree
{long long weight;int code;Tree *left;Tree *right;Tree(long long w,int c,Tree* a,Tree* b):weight(w),code(0),left(NULL),right(NULL){weight=w;left=a;right=b;code=c;}
};
/*
Huffman树建立的优先队列比较结构体
用于构建优先队列的排序顺序(按照频率由小到大排列)
*/
struct cmp
{  bool operator()(Tree *a,Tree *b)  {  return a->weight >= b->weight;            }
};
//统计ASCII码各字符在文件中出现的频率函数
void statistics(char *a)
{   FileLength=0;ifstream INPUT(a,ios::binary);                                              //打开文件 if(INPUT.fail())return;                                                     //如果文件不存在则返回 while(!INPUT.eof())                                                         //循环读取每一字节,存入temp中并统计频率 {       unsigned char temp;INPUT.read((char*)&temp,sizeof(unsigned char));if(!INPUT.eof()){node[(int)temp]++;FileLength++;}                   //如果未读至文件尾部则加对应码频率,同时文件长度统计加一 }INPUT.close();                                                              //关闭文件
}
//Huffman编码函数
void encode(Tree *root,string a)                                                //对树进行递归遍历编码
{      if(root->left==NULL&&root->right==NULL){m[root->code]=a;}                //如果搜索至叶子节点,将匹配信息存入m中 else {if(root->left!=NULL) {                                            //搜索左孩子并把字符串加'0’ a+='0';  encode(root->left,a);}if(root->right!=NULL) {                                           //搜索右孩子并把字符串加'1' a=a.substr(0,a.length()-1);a+='1';  encode(root->right,a);}}
}
//建立Huffman树函数
void creatTree(priority_queue<Tree*,vector<Tree*>,cmp> &forest)
{     for(int i=0;i<256;i++){if(node[i]!=0)                                                    //将非0的Huffman编码统计数据以节点的形式加入到队列中 {Tree *temp=new Tree(node[i],i,NULL,NULL);                   //建立新节点 forest.push(temp);                                          //加入队列中 }}while(1){       if(forest.size()==1) break;                                      //始终循环直到队列中剩余一个节点为止,建树完成 Tree *ltemp=forest.top();                                        //将优先队列的队前两元素取出并pop掉,将两个节点作为新节点的左右孩子 forest.pop(); Tree *rtemp=forest.top();forest.pop();Tree *temp=new Tree(ltemp->weight+rtemp->weight,0,ltemp,rtemp);  //新节点的频率为两个孩子节点的频率之和,新节点不需要代表任何源码 forest.push(temp);}
}
/*压缩函数
INPUT:打开源文件  OUTPUT:打开压缩文件
inByte:临时存储的读入字节 outByte:临时存储的写入字节
storage:等待被写入的信息  f:判断是否进行了压缩
大致流程为:统计频率、建立Huffman树、对Huffman树进行编码、重读文件依次对应写入新编码及最后补位
*/
void compress(char *a,char *b,int &f)
{    ifstream INPUT(a,ios::binary);                                             //打开源文件 if(INPUT.fail()){f=0;cout<<"对不起,您的压缩文件不存在!"<<endl;return;}ofstream OUTPUT(b,ios::binary);                                            //打开压缩文件预备写入 if(OUTPUT.fail())return;                                                                statistics(a);                                                             //统计字符出现的频率及文件长度 if(FileLength==0||FileLength==1){ f=0;cout<<"您的文件为空文件,无需压缩!"<<endl;return;}else if(FileLength<=10){ cout<<"友情提示:您的文件为小文件,压缩效果不会很理想!"<<endl;}priority_queue<Tree*,vector<Tree*>,cmp> forest;                             creatTree(forest);                                                         //优先队列建立Huffman树string str="";                                                             encode(forest.top(),str);                                                  //根据建树对Huffman树进行Huffman编码 OUTPUT.write((char*)&FileLength,sizeof(FileLength));                       //写入统计好的文件长度写入 for(int i=0;i<256;i++)                                                     //首先将统计频率信息写入文件,以便解压使用 {  OUTPUT.write((char*)&node[i],sizeof(node[i]));} string storage="";unsigned char inByte,outByte;while(!INPUT.eof()){while(storage.length()<8)                                       //扫描文件增添storage,存储信息超过八位跳出循环执行写入 {    if(INPUT.eof())break;INPUT.read((char *)&inByte,sizeof(inByte));if(!INPUT.eof())storage+=m[(int)inByte];                   //增加准备写入的Huffman编码                   }while(storage.length()>=8)                                      //写入编码 {outByte='\0';                                            //初始化写入字节 for(int i=0;i<8;i++)                                    //按位存入字节信息 {outByte<<=1;                                          //左移字节 if(storage[i]=='1') outByte|=1;                       //或操作写入1 }OUTPUT.write((char *)&outByte,sizeof(outByte));           //写入字节 storage=storage.substr(8);                                //写入8位后截掉storage的前8位 }if(INPUT.eof()&&storage.length()!=0)                            //如果读取至文件结尾后还未完成编码写入 {outByte='\0';for(int i=0;i<storage.length();i++)                    //剩余的位数写入 {outByte<<=1;if(storage[i]=='1')outByte|=1;}outByte<<=(8-storage.length());                         //补足8位操作 OUTPUT.write((char *)&outByte,sizeof(outByte));         //写入最后一位字节 }}INPUT.close ();OUTPUT.close ();}
/*解压函数
INPUT:打开压缩文件  OUTPUT:打开解压文件
inByte:临时存储的读入字节   outByte: 临时存储的写入字节
p:遍历Huffman树需要的指针   f:判断是否进行了解压
大致流程为:读取频率,重新建树,索引源码,写入文件
*/
void uncompress(char *a,char *b,int &f)
{   long long WriteLength=0;                                                    //统计已经写入的文件长度 ifstream INPUT(a,ios::binary);if(INPUT.fail()){f=0;cout<<"对不起,您的解压文件不存在!"<<endl;return;}ofstream OUTPUT(b,ios::binary);if(OUTPUT.fail())return;INPUT.read((char*)&FileLength,sizeof(FileLength));                          //读取源文件长度 for(int i=0;i<256;i++)                                                      //读取频率数组重新存入 {   INPUT.read((char*)&node[i],sizeof(node[i]));}priority_queue<Tree*,vector<Tree*>,cmp> forest;                             //优先队列建立Huffman树 creatTree(forest);        unsigned char inByte;Tree *p=forest.top();                                                       //指针指向Huffman树根节点预备遍历 while(!INPUT.eof()){      INPUT.read((char*)&inByte,sizeof(inByte));                           //按照字节读取if(!INPUT.eof()) {    for(int i=0;i<8;i++)                                           //按位解析处理 { int temp=inByte&128;                                      //与10000000进行与操作提取第一位 if(temp==128)                                             //第一位为1,遍历右孩子 {    p=p->right;if(p->left==NULL&&p->right==NULL)                    //如果遍历至叶子节点,读取节点中的源码写入文件 { unsigned char outByte=(char)p->code;OUTPUT.write((char*)&outByte,sizeof(outByte));WriteLength++;if(WriteLength==FileLength)break;                  //未读完最后的字节时若已经写毕文件则完成写入 p=forest.top();                                    //指针指回根节点 }}else                                                       //第一位为0,遍历左孩子 {    p=p->left;if(p->left==NULL&&p->right==NULL)                    //如果遍历至叶子节点,读取节点中的源码写入文件 { unsigned char outByte=(char)p->code;OUTPUT.write((char*)&outByte,sizeof(outByte));WriteLength++;if(WriteLength==FileLength)break;p=forest.top();                                    //指针指回根节点 }}inByte<<=1;                                                 //左移位 }}}INPUT.close();OUTPUT.close();}
int main()
{   clock_t start,end;while(1){    cout<<"使用说明:"<<endl;cout<<endl;cout<<"【1】压缩->【2】解压->【0】退出"<<endl;cout<<"************************************************************************"<<endl;cout<<endl;char a=getch(); if(a=='1'){         cout<<"【当前为压缩模式】"<<endl; memset(node,0,sizeof(node));cout<<"请输入待压缩文件路径:"; char inputFile[100];cin.getline(inputFile,100);cout<<"请输入目的路径:"; char outputFile[100];cin.getline(outputFile,100);cout<<"压缩中,请耐心等待..."<<endl;start=clock();int flag=1;compress(inputFile,outputFile,flag);end=clock();double cpu_time_used=((double)(end-start))/CLOCKS_PER_SEC;if(flag==1)cout<<"恭喜压缩成功!"<<"压缩用时:"<<cpu_time_used<<endl; }else if(a=='2'){        cout<<"【当前为解压缩模式】"<<endl; memset(node,0,sizeof(node));cout<<"请输入待解压文件路径:"; char outputFile1[100];cin.getline(outputFile1,100);cout<<"请输入目的路径:"; char outbackFile2[100];cin.getline(outbackFile2,100);cout<<"解压中,请耐心等待..."<<endl;start=clock();int flag=1;uncompress(outputFile1,outbackFile2,flag);end=clock();double cpu_time_used=((double)(end-start))/CLOCKS_PER_SEC;if(flag==1)cout<<"恭喜解压成功!"<<"解压用时:"<<cpu_time_used<<endl; }else break;system("pause");}return 0;
}

【算法】哈夫曼压缩算法-学习记录相关推荐

  1. 数据结构与算法(赫夫曼树,赫夫曼编码)

    赫夫曼树 基本介绍: (1)给定n个权值作为n给叶子节点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,称这样的二叉树为最优二叉树,也称哈夫曼树(HuffmanTree),还有的树翻译为霍夫 ...

  2. 数据结构与算法——赫夫曼树基本实现

    目录 一.赫夫曼树 1.1 基本介绍 1.2 赫夫曼树创建步骤图解 1.3  代码实现 二.赫夫曼编码 2.1 基本介绍 2.1.1  通讯领域 - 定长编码 - 举例说明 2.1.2  通讯领域 - ...

  3. 算法-16-哈夫曼编码

    十六.哈夫曼编码(Huffman Coding) 1.概念 它是哈夫曼树(Huffman Tree)在电讯通信领域中的经典应用.广泛应用于数据文件的压缩,压缩率一般在20% ~ 90%之间,属于**可 ...

  4. 数据结构与算法 / 霍夫曼树、霍夫曼编码和解码

    一. 诞生原因 找出存放一串字符所需的最少的二进制编码. 二. 构造方法 首先统计出每种字符出现的频率,即:概率.权值. 例如:频率表 A:60,    B:45,   C:13   D:69   E ...

  5. 贪心算法 - 哈夫曼编码 Huffman

    转载地址  :   http://blog.csdn.net/xuefeng0707/article/details/7844834 哈夫曼编码: 一种字符编码方式,常用于数据文件压缩.压缩率通常在2 ...

  6. 数据结构与算法--哈夫曼树及其应用

    一.哈夫曼树的基本概念 1) 路径: 从树中一个结点到另一个结点之间的分支构成这两个结点间的路径 2) 结点的路径长度: 两结点间路径上的分支数           3) 树的路径长度:从树根到每一个 ...

  7. 格子玻尔兹曼法学习记录(附MATLAB画图源程序)

    感谢群里的朋友们提供帮助!还是老样子,有啥问题Feel free to tell us~毕竟群众力量大嘛~格子玻尔兹曼救星QQ群:293267908. 流体计算领域中,LBM还是个比较新的思想,最近宝 ...

  8. 经典算法: 哈夫曼编码

    1.哈夫曼树的基本概念 从A结点到B结点所经过的分支序列叫做从A结点到B结点的路径:从A结点到B结点所经过的分支个数叫做从A结点到B结点的路径长度:从二叉树的根结点到二叉树中所有叶结点的路径长度之和称 ...

  9. 贪心算法哈夫曼编码c语言,贪心算法详解:哈夫曼编码

    理解贪心算法 贪心算法是一种算法思想,并不是一个具体的算法,因此我们用两个例子来理解什么样的问题适合用贪心算法解决. 例一 现在有一个能装 100g 物品的背包,和一些可拆分的物品(见表格),怎么装才 ...

最新文章

  1. awk2.0 — awk分隔符
  2. NOIP2008传纸条[DP]
  3. 值得收藏!脑科学、脑机接口领域白皮书、研究报告汇总
  4. 计划策略-20-订货型生产
  5. 获取webbrowser中元素的屏幕坐标
  6. 行驶在傍山的道路上_进藏线上那些唯美弯道,行驶中却充满风险,自驾游要注意几个事项...
  7. Linux 安装Python37
  8. mysql主从复制之异常解决--- Slave_IO_Running: NO
  9. SpringBoot之项目运行常见报错
  10. Quick Switch Virtual Desktop[AutoHotkey]
  11. 路径标记语法 in Windows Presentation Foundation(WPF)
  12. GridView中的格式化
  13. 吉米多维奇例题——(7)
  14. 计算机图标制作教程,电脑主题ICO图标制作方法 详细教程你一学就会
  15. 几个关于矩阵的定义 奇异值分解 谱分解
  16. 斐讯 K2 路由器 无线中继 无线扩展设置教程图文
  17. [应用漏洞]OpenSSH scp命令注入漏洞(CVE-2020-15778)
  18. SAP 常用增强记录文档
  19. Ubuntu下载常用软件和使用Caffe时的常见问题
  20. Cent OS网络基本配置——修改配置文件

热门文章

  1. vue使用 html2canvas 导出页面,及将图片转成 pdf 格式
  2. 数据中的知识发现KDD和机器学习概念
  3. UG4.0高级塑胶模具设计视频教程-陈工73G
  4. java用正则表达式判断一个字符串是否是车牌号
  5. Transformer模型
  6. 9.1 什么是包图?
  7. link和@import的区别:
  8. JAVA实现求和与求平均值运算
  9. css文本框圆角不兼容,CSS教程之重置默认样式与IE兼容圆角的解决方法
  10. 淦ORB-SLAM2源码 04--单目初始化Initializer.cc 干了啥事