⑴ 哈夫曼编码做压缩软件的问题c++
因为32个0、1是4个字节。(因为8个0、1是一个字节)
但是它这个东西算出来的是一个0、1占一个字节的那种
所以要变成32个0、1占4字节的那种
⑵ 一、实验题目:用哈夫曼编码实现文件压缩用C++实现 急用
这是我的实验报告:http://student.csdn.net/space.php?uid=395622&do=blog&id=51206/**
* @brief 哈夫曼编码
* @date 2010-11-30
*/
#include <iostream>
#include <string>
#include <queue>
#include <map>
using namespace std;
/**
* @brief 哈弗曼结点
* 记录了哈弗曼树结点的数据、权重及左右儿子
*/
struct HTNode {
char data;
HTNode *lc, *rc;
int w;
/** 节点构造函数 */
HTNode(char _d, int _w, HTNode *_l = NULL, HTNode *_r = NULL)
{
data = _d;
w = _w;
lc = _l;
rc = _r;
}
/** 节点拷贝构造函数 */
HTNode(const HTNode &h)
{
data = h.data;
lc = h.lc;
rc = h.rc;
w = h.w;
}
/** 用于优先队列比较的运算符重载 */
friend bool operator < (const HTNode &a, const HTNode &b)
{
return a.w > b.w;
}
};
/** 哈弗曼树叶子节点数、各叶子结点数据及权重 */
/** 权值从Lolita小说中抽样取出 */
const char ch[] = {
10, 32, 33, 37, 40, 41, 44, 45, 46, 48,
49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 63, 65, 66, 67, 68, 69, 70, 71, 72,
73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
83, 84, 85, 86, 87, 88, 89, 90, 91, 93,
97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
117, 118, 119, 120, 121, 122, 123, 161, 164, 166,
168, 170, 173, 174, 175, 176, 177, 180, 186, 255,
'\r', '\0'
};
const int fnum[] = {
2970, 99537, 265, 1, 496, 494, 9032, 1185, 5064, 108,
180, 132, 99, 105, 82, 64, 62, 77, 126, 296,
556, 548, 818, 443, 543, 435, 225, 271, 260, 797,
3487, 158, 50, 1053, 589, 498, 332, 316, 61, 276,
724, 855, 54, 293, 543, 11, 185, 11, 25, 26,
42416, 7856, 12699, 23670, 61127, 10229, 10651, 27912, 32809, 510,
4475, 23812, 13993, 34096, 38387, 9619, 500, 30592, 30504, 42377,
14571, 4790, 11114, 769, 10394, 611, 1, 4397, 12, 71,
117, 1234, 81, 5, 852, 1116, 1109, 1, 3, 1,
2970
};
const int n = 91;
/** 优先队列 */
priority_queue<HTNode> pq;
/** 哈弗曼编码映射 */
map<string, char> dcode;
map<char, string> ecode;
/** 根节点以及总权重+边长 */
HTNode *root;
int sum = 0;
/** 初始化叶节点,并加入到优先队列中 */
void Init()
{
for(int i = 0; i < n; i++)
{
HTNode p(ch[i], fnum[i]);
pq.push(p);
}
}
/** 建立哈夫曼树 */
void CreateHT()
{
HTNode *lmin, *rmin;
/** 当队列中不止一个元素时 */
while(!pq.empty() && 1 != pq.size())
{
/** 取队首两个元素(权值最小) */
lmin = new HTNode(pq.top());
pq.pop();
rmin = new HTNode(pq.top());
pq.pop();
/** 合并元素重新入队 */
HTNode p(0, lmin->w + rmin->w, lmin, rmin);
pq.push(p);
}
if(!pq.empty())
{
/** 根节点 */
root = new HTNode(pq.top());
pq.pop();
}
}
/** 创建哈夫曼编码 */
void CreateHTCode(HTNode *p, string str)
{
if(!p) return;
if(0 != p->data)
{
/** 若是叶节点,则记录此节点的编码值 */
dcode[str] = p->data;
ecode[p->data] = str;
sum += (str.length() * p->w);
return;
}
CreateHTCode(p->lc, str + "0");
CreateHTCode(p->rc, str + "1");
}
/** 显示哈夫曼编码 */
void DispCode()
{
printf("输出哈弗曼编码:\n");
for(int i = 0; i < n; i++)
{
printf("\t'%c':\t%s\n", ch[i], ecode[ch[i]].c_str());
}
printf("平均长度:%.5lf\n", double(sum) / double(root->w));
}
/** 释放哈夫曼树 */
void Release(HTNode *p)
{
if(!p) return;
Release(p->lc);
Release(p->rc);
delete p;
}
/** 输出压缩文 */
void putEncode(FILE *fp, char *buf)
{
unsigned char code = 0;
for(int i = 0; i < 8; i++)
code = (code << 1) + (buf[i] - '0');
fwrite(&code, sizeof(unsigned char), 1, fp);
}
/** 判断是否在字符串内 */
bool instr(char c, const char str[])
{
for(int i = 0; i < strlen(str); i++)
if(c == str[i]) return true;
return false;
}
/** 压缩文件 */
void Encode()
{
FILE *OF;
FILE *IF;
char ifn[255];
const char ofn[] = "Encode.txt";
char buf[9];
int cnt = 0, newcnt = 0;
printf("Input the filename: ");
scanf("%s", ifn);
IF = fopen(ifn, "rb");
if(!IF)
{
printf("Wrong file.\n");
return;
}
OF = fopen(ofn, "wb+");
if(!OF)
{
printf("Wrong file.\n");
}
/** 开始读文件 */
memset(buf, 0, sizeof(buf));
while(!feof(IF))
{
unsigned char c;
fread(&c, sizeof(unsigned char), 1, IF);
if(instr(c, ch));
else c = ' ';
for(int i = 0; i < ecode[c].length(); i++)
{
buf[strlen(buf)] = ecode[c][i];
if(8 == strlen(buf))
{
newcnt++;
putEncode(OF, buf);
memset(buf, 0, sizeof(buf));
}
}
cnt++;
}
cnt--;
if(0 != strlen(buf))
{
for(int i = strlen(buf); i < 8; i++) buf[i] = '0';
putEncode(OF, buf);
}
fwrite(&cnt, 4, 1, OF);
fclose(IF);
fclose(OF);
printf("压缩成功!压缩率:%.2f%c\n", (((double)newcnt + 4.0f) / (double)cnt) * 100, '%');
}
/** 补0 */
void putZeros(char *buf)
{
char tmpbuf[9];
memset(tmpbuf, 0, sizeof(tmpbuf));
if(8 != strlen(buf))
{
for(int i = 0; i < 8 - strlen(buf); i++) tmpbuf[i] = '0';
strcat(tmpbuf, buf);
strcpy(buf, tmpbuf);
}
}
/** 解压缩 */
void Decode()
{
char buf[256];
char oldbuf[9];
const char ifn[] = "Encode.txt";
const char ofn[] = "Decode.txt";
FILE *IF = fopen(ifn, "rb");
if(!IF)
{
printf("Wrong file.\n");
return;
}
FILE *OF = fopen(ofn, "wb+");
if(!OF)
{
printf("Wrong file.\n");
return;
}
int tot, cnt = 0;
fseek(IF, -4L, SEEK_END);
fread(&tot, 4, 1, IF);
fseek(IF, 0L, SEEK_SET);
memset(buf, 0, sizeof(buf));
while(true)
{
if(cnt == tot) break;
unsigned char c;
fread(&c, sizeof(unsigned char), 1, IF);
itoa(c, oldbuf, 2);
putZeros(oldbuf);
for(int i = 0; i < 8; i++)
{
if(cnt == tot) break;
buf[strlen(buf)] = oldbuf[i];
if(dcode.end() != dcode.find(string(buf)))
{
fwrite(&dcode[string(buf)], sizeof(char), 1, OF);
memset(buf, 0, sizeof(buf));
cnt++;
}
}
}
fclose(IF);
fclose(OF);
printf("解压成功!文件名Decode.txt。\n");
}
int main()
{
Init();
CreateHT();
CreateHTCode(root, "");
DispCode();
Encode();
Decode();
Release(root);
system("pause");
return 0;
}
⑶ 用哈夫曼编码压缩一个word文档,文件没有变小,反而还变大了
提问者尼壕,
哈夫曼编码是可以应用于数据压缩
但可能文件本身被压缩,比如docx文件,本身已经被压缩le,所以基本没有效果,甚至变大
好比7z压缩一个avc mp4一样,只会变大
但doc应该有一定效果
有问题请追问撒QAQ
⑷ 如何用哈夫曼编码制作压缩解压缩软件
去问小翠啊, 望采纳,记得给分
⑸ 有关哈夫曼编码压缩与解压缩的问题.
压缩代码非常简单,首先用ASCII值初始化511个哈夫曼节点:
CHuffmanNode nodes[511];
for(int nCount = 0; nCount < 256; nCount++)
nodes[nCount].byAscii = nCount;
然后,计算在输入缓冲区数据中,每个ASCII码出现的频率:
for(nCount = 0; nCount < nSrcLen; nCount++)
nodes[pSrc[nCount]].nFrequency++;
然后,根据频率进行排序:
qsort(nodes, 256, sizeof(CHuffmanNode), frequencyCompare);
现在,构造哈夫曼树,获取每个ASCII码对应的位序列:
int nNodeCount = GetHuffmanTree(nodes);
构造哈夫曼树非常简单,将所有的节点放到一个队列中,用一个节点替换两个频率最低的节点,新节点的频率就是这两个节点的频率之和。这样,新节点就是两个被替换节点的父节点了。如此循环,直到队列中只剩一个节点(树根)。
// parent node
pNode = &nodes[nParentNode++];
// pop first child
pNode->pLeft = PopNode(pNodes, nBackNode--, false);
// pop second child
pNode->pRight = PopNode(pNodes, nBackNode--, true);
// adjust parent of the two poped nodes
pNode->pLeft->pParent = pNode->pRight->pParent = pNode;
// adjust parent frequency
pNode->nFrequency = pNode->pLeft->nFrequency + pNode->pRight->nFrequency;
这里我用了一个好的诀窍来避免使用任何队列组件。我先前就直到ASCII码只有256个,但我分配了511个(CHuffmanNode nodes[511]),前255个记录ASCII码,而用后255个记录哈夫曼树中的父节点。并且在构造树的时候只使用一个指针数组(ChuffmanNode *pNodes[256])来指向这些节点。同样使用两个变量来操作队列索引(int nParentNode = nNodeCount;nBackNode = nNodeCount –1)。
接着,压缩的最后一步是将每个ASCII编码写入输出缓冲区中:
int nDesIndex = 0;
// loop to write codes
for(nCount = 0; nCount < nSrcLen; nCount++)
{
*(DWORD*)(pDesPtr+(nDesIndex>>3)) |=
nodes[pSrc[nCount]].dwCode << (nDesIndex&7);
nDesIndex += nodes[pSrc[nCount]].nCodeLength;
}
(nDesIndex>>3): >>3 以8位为界限右移后到达右边字节的前面
(nDesIndex&7): &7 得到最高位.
注意:在压缩缓冲区中,我们必须保存哈夫曼树的节点以及位序列,这样我们才能在解压缩时重新构造哈夫曼树(只需保存ASCII值和对应的位序列)。
解压缩
解压缩比构造哈夫曼树要简单的多,将输入缓冲区中的每个编码用对应的ASCII码逐个替换就可以了。只要记住,这里的输入缓冲区是一个包含每个ASCII值的编码的位流。因此,为了用ASCII值替换编码,我们必须用位流搜索哈夫曼树,直到发现一个叶节点,然后将它的ASCII值添加到输出缓冲区中:
int nDesIndex = 0;
DWORD nCode;
while(nDesIndex < nDesLen)
{
nCode = (*(DWORD*)(pSrc+(nSrcIndex>>3)))>>(nSrcIndex&7);
pNode = pRoot;
while(pNode->pLeft)
{
pNode = (nCode&1) ? pNode->pRight : pNode->pLeft;
nCode >>= 1;
nSrcIndex++;
}
pDes[nDesIndex++] = pNode->byAscii;
}
过程
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
#include<math.h>
#define M 10
typedef struct Fano_Node
{
char ch;
float weight;
}FanoNode[M];
typedef struct node
{
int start;
int end;
struct node *next;
}LinkQueueNode;
typedef struct
{
LinkQueueNode *front;
LinkQueueNode *rear;
}LinkQueue;
void EnterQueue(LinkQueue *q,int s,int e)
{
LinkQueueNode *NewNode;
NewNode=(LinkQueueNode *)malloc(sizeof(LinkQueueNode));
if(NewNode!=NULL)
{
NewNode->start=s;
NewNode->end=e;
NewNode->next=NULL;
q->rear->next=NewNode;
q->rear=NewNode;
}
else printf("Error!");
}
//***按权分组***//
void Divide(FanoNode f,int s,int *m,int e)
{
int i;
float sum,sum1;
sum=0;
for(i=s;i<=e;i++)
sum+=f.weight;
*m=s;
sum1=0;
for(i=s;i<e;i++)
{
sum1+=f.weight;
*m=fabs(sum-2*sum1)>fabs(sum-2*sum1-2*f.weight)?(i+1):*m;
if(*m==i)
break;
}
}
main()
{
int i,j,n,max,m,h[M];
int sta,mid,end;
float w;
char c,fc[M][M];
FanoNode FN;
LinkQueueNode *p;
LinkQueue *Q;
//***初始化队Q***//
Q->front=(LinkQueueNode *)malloc(sizeof(LinkQueueNode));
Q->rear=Q->front;
Q->front->next=NULL;
printf("\t***FanoCoding***\n");
printf("Please input the number of node:"); /*输入信息*/
scanf("%d",&n);
i=1;
while(i<=n)
{
printf("%d weight and node:",i);
scanf("%f %c",&FN.weight,&FN.ch);
for(j=1;j<i;j++)
{
if(FN.ch==FN[j].ch)
{
printf("Same node!!!\n");
break;
}
}
if(i==j)
i++;
}
for(i=1;i<=n;i++) /*排序*/
{
max=i+1;
for(j=max;j<=n;j++)
max=FN[max].weight<FN[j].weight?j:max;
if(FN.weight<FN[max].weight)
{
w=FN.weight;
FN.weight=FN[max].weight;
FN[max].weight=w;
c=FN.ch;
FN.ch=FN[max].ch;
FN[max].ch=c;
}
}
for(i=1;i<=n;i++) /*初始化h*/
h=0;
EnterQueue(Q,1,n); /*1和n进队*/
while(Q->front->next!=NULL)
{
p=Q->front->next; /*出队*/
Q->front->next=p->next;
if(p==Q->rear)
Q->rear=Q->front;
sta=p->start;
end=p->end;
free(p);
Divide(FN,sta,&m,end); /*按权分组*/
for(i=sta;i<=m;i++)
{
fc[h]='0';
h++;
}
if(sta!=m)
EnterQueue(Q,sta,m);
else
fc[sta][h[sta]]='\0';
for(i=m+1;i<=end;i++)
{
fc[h]='1';
h++;
}
if(m==sta&&(m+1)==end) //如果分组后首元素的下标与中间元素的相等,
{ //并且和最后元素的下标相差为1,则编码码字字符串结束
fc[m][h[m]]='\0';
fc[end][h[end]]='\0';
}
else
EnterQueue(Q,m+1,end);
}
for(i=1;i<=n;i++) /*打印编码信息*/
{
printf("%c:",FN.ch);
printf("%s\n",fc);
}
system("pause");
}
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<string.h>
#define N 100
#define M 2*N-1
typedef char * HuffmanCode[2*M];
typedef struct
{
char weight;
int parent;
int LChild;
int RChild;
}HTNode,Huffman[M+1];
typedef struct Node
{
int weight; /*叶子结点的权值*/
char c; /*叶子结点*/
int num; /*叶子结点的二进制码的长度*/
}WNode,WeightNode[N];
/***产生叶子结点的字符和权值***/
void CreateWeight(char ch[],int *s,WeightNode *CW,int *p)
{
int i,j,k;
int tag;
*p=0;
for(i=0;ch!='\0';i++)
{
tag=1;
for(j=0;j<i;j++)
if(ch[j]==ch)
{
tag=0;
break;
}
if(tag)
{
(*CW)[++*p].c=ch;
(*CW)[*p].weight=1;
for(k=i+1;ch[k]!='\0';k++)
if(ch==ch[k])
(*CW)[*p].weight++;
}
}
*s=i;
}
/********创建HuffmanTree********/
void CreateHuffmanTree(Huffman *ht,WeightNode w,int n)
{
int i,j;
int s1,s2;
for(i=1;i<=n;i++)
{
(*ht).weight =w.weight;
(*ht).parent=0;
(*ht).LChild=0;
(*ht).RChild=0;
}
for(i=n+1;i<=2*n-1;i++)
{
(*ht).weight=0;
(*ht).parent=0;
(*ht).LChild=0;
(*ht).parent=0;
}
for(i=n+1;i<=2*n-1;i++)
{
for(j=1;j<=i-1;j++)
if(!(*ht)[j].parent)
break;
s1=j; /*找到第一个双亲不为零的结点*/
for(;j<=i-1;j++)
if(!(*ht)[j].parent)
s1=(*ht)[s1].weight>(*ht)[j].weight?j:s1;
(*ht)[s1].parent=i;
(*ht).LChild=s1;
for(j=1;j<=i-1;j++)
if(!(*ht)[j].parent)
break;
s2=j; /*找到第一个双亲不为零的结点*/
for(;j<=i-1;j++)
if(!(*ht)[j].parent)
s2=(*ht)[s2].weight>(*ht)[j].weight?j:s2;
(*ht)[s2].parent=i;
(*ht).RChild=s2;
(*ht).weight=(*ht)[s1].weight+(*ht)[s2].weight;
}
}
/***********叶子结点的编码***********/
void CrtHuffmanNodeCode(Huffman ht,char ch[],HuffmanCode *h,WeightNode *weight,int m,int n)
{
int i,j,k,c,p,start;
char *cd;
cd=(char *)malloc(n*sizeof(char));
cd[n-1]='\0';
for(i=1;i<=n;i++)
{
start=n-1;
c=i;
p=ht.parent;
while(p)
{
start--;
if(ht[p].LChild==c)
cd[start]='0';
else
cd[start]='1';
c=p;
p=ht[p].parent;
}
(*weight).num=n-start;
(*h)=(char *)malloc((n-start)*sizeof(char));
p=-1;
strcpy((*h),&cd[start]);
}
system("pause");
}
/*********所有字符的编码*********/
void CrtHuffmanCode(char ch[],HuffmanCode h,HuffmanCode *hc,WeightNode weight,int n,int m)
{
int i,j,k;
for(i=0;i<m;i++)
{
for(k=1;k<=n;k++) /*从(*weight)[k].c中查找与ch相等的下标K*/
if(ch==weight[k].c)
break;
(*hc)=(char *)malloc((weight[k].num+1)*sizeof(char));
for(j=0;j<=weight[k].num;j++)
(*hc)[j]=h[k][j];
}
}
/*****解码*****/
void TrsHuffmanTree(Huffman ht,WeightNode w,HuffmanCode hc,int n,int m)
{
int i=0,j,p;
printf("***StringInformation***\n");
while(i<m)
{
p=2*n-1;
for(j=0;hc[j]!='\0';j++)
{
if(hc[j]=='0')
p=ht[p].LChild;
else
p=ht[p].RChild;
}
printf("%c",w[p].c); /*打印原信息*/
i++;
}
}
main()
{
int i,n,m,s1,s2,j; /*n为叶子结点的个数*/
char ch[N],w[N]; /*ch[N]存放输入的字符串*/
Huffman ht; /*二叉数 */
HuffmanCode h,hc; /* h存放叶子结点的编码,hc 存放所有结点的编码*/
WeightNode weight; /*存放叶子结点的信息*/
printf("\t***HuffmanCoding***\n");
printf("please input information :");
gets(ch); /*输入字符串*/
CreateWeight(ch,&m,&weight,&n); /*产生叶子结点信息,m为字符串ch[]的长度*/
printf("***WeightInformation***\n Node "); /*输出叶子结点的字符与权值*/
for(i=1;i<=n;i++)
printf("%c ",weight.c);
printf("\nWeight ");
for(i=1;i<=n;i++)
printf("%d ",weight.weight);
CreateHuffmanTree(&ht,weight,n); /*产生Huffman树*/
printf("\n***HuffamnTreeInformation***\n");
for(i=1;i<=2*n-1;i++) /*打印Huffman树的信息*/
printf("\t%d %d %d %d\n",i,ht.weight,ht.parent,ht.LChild,ht.RChild);
CrtHuffmanNodeCode(ht,ch,&h,&weight,m,n); /*叶子结点的编码*/
printf(" ***NodeCode***\n"); /*打印叶子结点的编码*/
for(i=1;i<=n;i++)
{
printf("\t%c:",weight.c);
printf("%s\n",h);
}
CrtHuffmanCode(ch,h,&hc,weight,n,m); /*所有字符的编码*/
printf("***StringCode***\n"); /*打印字符串的编码*/
for(i=0;i<m;i++)
printf("%s",hc);
system("pause");
TrsHuffmanTree(ht,weight,hc,n,m); /*解码*/
system("pause");
}
⑹ 在哈夫曼编码压缩程序中应该如何存储哈夫曼编码
我想你理解错了……你所说的128Bit是编码和解码时用的
树怎么保存,方法很多,最简单的办法是为0x00到0xFF按它们出现的频率保存顺序;因为只有256个元素,所以用1字节就能保存到它们的顺序,例如
0x00 0x05
0x01 0x04
0x02 0xF5
……
……
要保存这种表示方式也只是要512字节而已;重建树的时候重再根据这些数据来把树创建出来就是了;
最后建议你把哈夫曼编码原理重新再看一次,是看“原理”
⑺ Huffman编码可以破解加密的压缩文件嘛
你说的应该是WinRAR这个软件加密的压缩文件吧。
Huffman编码是不可也破解的,Huffman编码可以压缩与解压缩文件,只有用Huffman编码压缩的文件才能用Huffman编码解压缩。简单讲,就是用Huffman编码加密的文件,才能用Huffman编码解密。
WinRAR这个软件加密的压缩文件是目前比较安全的加密,目前网上已知的破解方法只有暴力破解。理论上讲,密码都可以用暴力破解出来;实际上,11位以上的密码,包含数字、字母、符号的密码是无法破解出来的。
如果你的密码是纯数字(9位以下,包含9位),一般可以破解出来。
⑻ 利用huffman编码对文件进行压缩,不同文件类型压缩率有差别的原因
1. 文本文件,二进制文件及数据流的操作
2. 英文字符,中文字符的存储与识别【难点】
3. 压缩及解压的主要思想【重点】
4. Huffman树的构造
5. 编码的获取
6. 压缩文件的存储形式[huffman编码信息及数据存储]
7. 对文本文件最后一个字符的处理[补位数:压缩,解压无错误]
⑼ 有人能给我一份哈夫曼编码的压缩和解压么
把要压缩或要解压的文件拖拽到窗口中即可。另存为编辑框是压缩或解压的输出路径。对于压缩来说,另存为路径是目标文件的路径加上一个.shc扩展名。对于解压来说,会去掉最后一个扩展名。
压缩的核心其实就是用了哈夫曼编码原理。我封装了一个哈夫曼编码类,内部使用了一个哈夫曼树类。
要对一个文件进行压缩,执行如下步骤:
1.建立编码方案。第一遍扫描文件,统计这个文件中各种不同的字节出现的次数(256种),以这个次数作为权值,建立对应的哈夫曼树。然后取得每个不同字节对应的01编码序列。