导航:首页 > 源码编译 > 哈夫曼编译码论文

哈夫曼编译码论文

发布时间:2023-05-17 18:11:50

1. 哈夫曼编码原理

赫夫曼码的码字(各符号的代码)是异前置码字,即任一码字不会是另一码字的前面部分,这使各码字可以连在一起传送,中间不需另加隔离符号,只要传送时不出错,收端仍可分离各个码字,不致混淆。

哈夫曼编码,又称霍夫曼编码,是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码。

(1)哈夫曼编译码论文扩展阅读

赫夫曼编码的具体方法:先按出现的概率大小排队,把两个最小的概率相加,作为新的概率
和剩余的概率重新排队,再把最小的两个概率相加,再重新排队,直到最后变成1。

每次相
加时都将“0”和“1”赋与相加的两个概率,读出时由该符号开始一直走到最后的“1”,
将路线上所遇到的“0”和“1”按最低位到最高位的顺序排好,就是该符号的赫夫曼编码。

例如a7从左至右,由U至U″″,其码字为1000;

a6按路线将所遇到的“0”和“1”按最低位到最高位的顺序排好,其码字为1001…

用赫夫曼编码所得的平均比特率为:Σ码长×出现概率

上例为:0.2×2+0.19×2+0.18×3+0.17×3+0.15×3+0.1×4+0.01×4=2.72 bit

可以算出本例的信源熵为2.61bit,二者已经是很接近了。

2. 哈夫曼编码

/* algo6-1.c 求哈夫纤搏颤曼编码。实现算法6.12的程序 */
//------------------- 公用的常量和类型 ----------------------------
#include<stdio.h>
#include <malloc.h>
#include <银茄stdlib.h>
#include <string.h>
//函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define UINT_MAX 1000
typedef int Status;

/* c6-7.h 哈夫曼树和哈夫曼编码的存储表示 */
typedef struct HTNode
{
char leaf;
unsigned int weight;
unsigned int parent,lchild,rchild;
}HTNode,*HuffmanTree; /* 动态分配数组存储哈夫曼编码表 */

typedef char **HuffmanCode; /* 动态分配数组存储哈夫曼编码表 */
typedef struct Node
{
char leaf;
unsigned int weight;
struct Node * next;
}LeafNode,*LeafLink;

typedef struct
{
LeafLink head;
unsigned len;
}LeafLinkList;

int min1(HuffmanTree t,int i)
{ /* 函数void select()调用 */
int j,flag;
unsigned int k=UINT_MAX; /* 取k为毁败不小于可能的值 */
for(j=1;j<=i;j++)
if(t[j].weight<k&&t[j].parent==0)
k=t[j].weight,flag=j;
t[flag].parent=1;
return flag;
}

void select(HuffmanTree t,int i,int *s1,int *s2)
{ /* s1为最小的两个值中序号小的那个 */
int j;
*s1=min1(t,i);
*s2=min1(t,i);
if(*s1>*s2)
{
j=*s1;
*s1=*s2;
*s2=j;
}
}

void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC, LeafLinkList L) /* 算法6.12 */
{ /* w存放n个字符的权值(权值均需大于0),构造哈夫曼树HT,并求出n个字符的哈夫曼编码HC*/
int m,i,s1,s2,start;
int n=L.len;
unsigned c,f;
LeafLink ptr;
HuffmanTree p;
char *cd;
if(n<=1)
return;
m=2*n-1;
printf("表长为%d\t哈夫曼树含节点数为%d\n",n,m);
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); /* 0号单元未用 */
ptr=L.head->next;
for(p=HT+1,i=1;i<=n;++i,++p,ptr=ptr->next)
{
(*p).leaf=ptr->leaf;
printf("%d\t",(*p).leaf);
(*p).weight=ptr->weight;
printf("%d\n",(*p).weight);
(*p).parent=0;
(*p).lchild=0;
(*p).rchild=0;
}
for(;i<=m;++i,++p)
{
(*p).parent=0;
(*p).leaf=0;
}
for(i=n+1;i<=m;++i) /* 建哈夫曼树 */
{ /* 在HT[1~i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2 */
select(HT,i-1,&s1,&s2);
HT[s1].parent=HT[s2].parent=i;
HT[i].lchild=s1;
HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;
}
/* 从叶子到根逆向求每个字符的哈夫曼编码 */
HC=(HuffmanCode)malloc((n+1)*sizeof(char*));
/* 分配n个字符编码的头指针向量([0]不用) */
cd=(char*)malloc(n*sizeof(char)); /* 分配求编码的工作空间 */
cd[n-1]='\0'; /* 编码结束符 */
for(i=1;i<=n;i++)
{ /* 逐个字符求哈夫曼编码 */
start=n-1; /* 编码结束符位置 */
for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent)
/* 从叶子到根逆向求编码 */
if(HT[f].lchild==c)
cd[--start]='0';
else
cd[--start]='1';
HC[i]=(char*)malloc((n-start)*sizeof(char));
/* 为第i个字符编码分配空间 */
strcpy(HC[i],&cd[start]); /* 从cd复制编码(串)到HC */
}
free(cd); /* 释放工作空间 */
for(i=1;i<=n;i++)
{
printf("%c编码为%s:\n",HT[i].leaf,HC[i]);
}
}

void InitLeafList(LeafLinkList &L)
{
L.head=(LeafLink)malloc(sizeof(LeafLink));
L.head->next=NULL;
L.len=0;
}
void PrintList(LeafLinkList L)
{
LeafLink p;
p=L.head->next;
printf("打印链表\n");
printf("表长为%d\n",L.len);
while(p!=NULL)
{
printf("%c or %d,%u\t",p->leaf,p->leaf,p->weight);
printf("打印一个节点\n");
p=p->next;
}
printf("打印结束\n");
printf("\n");
}

void EnLeafList(LeafLinkList &L,char ch)
{
LeafLink p,pre,temp;
int flag=0;
pre=p=L.head;
printf("%d即为%c******\n\n",ch,ch);
if(p->next==NULL) //p->next=NULL则为第一次插入操作
{
printf("第一次插入\n");
temp=(LeafLink)malloc(sizeof(LeafNode));
temp->leaf=ch;
temp->weight=1;
temp->next=NULL;
p->next=temp;
L.len++;
}

else
{

p=p->next;
while(p!=NULL)
{

if(ch==p->leaf)
{
p->weight++;
printf("加权\n");
p=NULL;
flag=1;
} //权重加一
else if(ch<p->leaf) //插入
{
printf("插入A\n");
temp=(LeafLink)malloc(sizeof(LeafNode));
temp->leaf=ch;
temp->weight=1;
temp->next=p;
pre->next=temp;
L.len++;
flag=1;
p=NULL;
}
else //继续寻找插入点
{
pre=p;
p=p->next;
}
}

if(p==NULL&&flag!=1) //若p=NULL则插到链尾
{
printf("插入B\n");
temp=(LeafLink)malloc(sizeof(LeafNode));
temp->leaf=ch;
temp->weight=1;
temp->next=NULL;
pre->next=temp;
L.len++;
}
}

}
void EnCoding()
{
FILE *fp,*fr,*fc;
HuffmanTree HT;
HuffmanCode HC;
int i,n;
LeafLinkList L;
InitLeafList(L);
char filename[15];
char ch;
printf("请输入文件名:\n ");
scanf("%s",filename);
if( !(fp=fopen(filename,"r")) )
{
printf("打开文件失败,请输入正确的文件名!! ");
exit(0);
}
ch=getchar(); //接收执行scanf语句时最后输入的回车符
printf("文件已经打开\n");
while(!feof(fp))
{

ch=fgetc(fp);
if(ch==-1)
{
printf("结束统计\n");
}
else
{
EnLeafList(L,ch);
}
}
PrintList(L);
HuffmanCoding(HT,HC, L);
n=L.len;
for(i=1;i<=n;i++)
{
puts(HC[i]);
}
char TreeName[15];
printf("把哈夫曼树存入文件,请输入文件名:\n ");
scanf("%s",TreeName);
if( !(fr=fopen(TreeName,"wb")) )
{
printf("打开文件失败,请输入正确的文件名!! ");
exit(0);
}
ch=getchar(); //接收执行scanf语句时最后输入的回车符
printf("文件已经打开\n");
//把哈夫曼树存入文件
printf("%d\n",n);
printf("把树的长度先存入\n");
putw(n,fr); //把树的长度先存入
for(i=1;i<=2*n-1;i++)
if(fwrite(&HT[i],sizeof(struct HTNode),1,fr)!=1)
printf("文件写入出错\n");
fclose(fr);

printf("打印原来的树\n");
for(i=1;i<=2*n-1;i++)
printf("%c %u %u %u %u\n",HT[i].leaf ,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild );
fclose(fr);

printf("把编码结果存入文件,请输入文件名:\n ");
char CodeFileName[15];
scanf("%s",CodeFileName);
if( !(fc=fopen(CodeFileName,"wb")) )
{
printf("打开文件失败,请输入正确的文件名!! ");
exit(0);
}
ch=getchar(); //接收执行scanf语句时最后输入的回车符

printf("待编码的文件位置指针重新指向开始位置\n");
printf("对待编码文件进行编码,编码同步显示,并将结果存入指定的文件\n");
rewind(fp);
while(!feof(fp))
{

ch=fgetc(fp);
printf("%c\n",ch);
if(ch==-1)
{
printf("结束编码\n");
}
else
{
for(int tap=0,i=1;tap==0&&i<=n;) //查找,该叶子对应的编码串
{
if(ch==HT[i].leaf) //找到,打印出对应的编码,并存入文件
{
printf("%s\n",HC[i]);
fputs(HC[i],fc); //将编码字符串存入文件

tap=1;
}
else
{
i++;
}
}
}
}
fclose(fp); //关闭文件
fclose(fc); //关闭文件
}
int decode(FILE *fc,HuffmanTree HT,int n)
{
while(!feof(fc))
{
char ch=fgetc(fc);
if(ch=='0')
{
n=HT[n].lchild;
if(HT[n].leaf!=0)
{
printf("%c",HT[n].leaf);
return OK;
}
else
{
decode(fc,HT,n);
return OK;
}
}
else if(ch=='1')
{

n=HT[n].rchild;
if(HT[n].leaf!=0)
{
printf("%c",HT[n].leaf);
return OK;
}
else
{
decode(fc,HT,n);
return OK;
}
}
else return OK;
}
return ERROR;
}

void Decoding() //解码文件,并将结果显示出来
{
FILE *fc,*fr;
char CodeFileName[15],ch,TreeName[15];
int i;
printf("解码文件,请输入文件名(如*.dat):\n ");
scanf("%s",CodeFileName);
if( !(fc=fopen(CodeFileName,"r")) )
{
printf("打开文件失败,请输入正确的文件名!! ");
exit(0);
}
ch=getchar(); //接收执行scanf语句时最后输入的回车符
printf("存放编码结果文件已经打开\n");

//读入哈夫曼树

HuffmanTree HT;
printf("取出对应的哈夫曼树文件,请输入文件名,\n");
scanf("%s",TreeName);
if( !(fr=fopen(TreeName,"rb")) ) //打开存放哈夫曼树的文件
{
printf("打开文件失败,请输入正确的文件名!! ");
exit(0);
}
int n=getw(fr); //将叶子数目取出
printf("叶子数目%d\n",n);
HT=(HuffmanTree)malloc((2*n)*sizeof(HTNode)); /* 然后分配空间,0号单元未用 */

for(i=1;i<=2*n-1;i++)
if(fread(&HT[i],sizeof(struct HTNode),1,fr)!=1)
printf("文件读出出错\n");
int length=2*n-1; //总长度
printf("总结点数目为:%d\n",n);
printf("该文件译码后得到的源文件为:\n");
printf("**************************************\n");
while(!feof(fc))
{
decode(fc,HT,length);
}
printf("**************************************\n");
printf("\n\n");
}

int PreOrderPrint(HuffmanTree HT,int n,int count)
{
if(HT[n].lchild)
{
for(int i=0;i<count;i++)
printf(" ");
printf("%u\n",HT[n].weight);
if( PreOrderPrint(HT,HT[n].lchild, ++count) )
if (PreOrderPrint(HT,HT[n].rchild, ++count))
return OK;
return ERROR;
}
else return OK;
}
void PrintTree()
{
//读入哈夫曼树
FILE *fr;
char TreeName[15];
HuffmanTree HT;
printf("取出对应的哈夫曼树文件(如*.dat),请输入文件名,\n");
scanf("%s",TreeName);
if( !(fr=fopen(TreeName,"rb")) ) //打开存放哈夫曼树的文件
{
printf("打开文件失败,请输入正确的文件名!! ");
exit(0);
}
int n=getw(fr); //将叶子数目取出
printf("含叶子数%d\n",n);
HT=(HuffmanTree)malloc((2*n)*sizeof(HTNode)); /* 然后分配空间,0号单元未用 */

for(int i=1;i<=2*n-1;i++)
if(fread(&HT[i],sizeof(struct HTNode),1,fr)!=1)
printf("文件读出出错\n");
int count=0;
n=2*n-1;
printf("总结点数目为;%d\n",n);
printf("哈夫曼树的存储形式为:\n");
for(i=1;i<=n;i++)
{
printf("%c,%u,%u,%u,%u\n",HT[i].leaf,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);
}
printf("哈夫曼树的凹入表形式为:\n");
PreOrderPrint(HT,n,count);
}
void PrintCodeFile()
{
FILE *fc;
printf("打印编码后的文件,请输入文件名(如*.dat):\n ");
char CodeFileName[15];
scanf("%s",CodeFileName);

if( !(fc=fopen(CodeFileName,"r")) )
{
printf("打开文件失败,请输入正确的文件名!! ");
exit(0);
}

char ch=getchar(); //接收执行scanf语句时最后输入的回车符
printf("打印编码后的文件,打印方法一\n");
int flag=1;
while(!feof(fc))
{

ch=fgetc(fc);
if(ch==-1)
{
printf("结束打印\n");
}
else
{
printf("%c",ch);
if(flag<=49)
flag++;
else
{
flag=1;
printf("\n");
}
}
}
printf("打印编码后的文件,打印方法二\n");
rewind(fc);
char str[50];
while(!feof(fc))
{
fgets(str,51,fc);
puts(str);
}
fclose(fc); //关闭文件
}

void Initialization() //系统初始化
{
printf("**************************************\n");
printf("*编码文件请输入e\n*译码文件请输入d\n*打印编码后的文件请输入p\n*打印哈夫曼树请输入t\n*结束请输入q \n");
printf("**************************************\n");
printf("\n\n\t\t字符:\n\n\n");
printf("**************************************\n");
printf("* 输入一个字符:e,d,p,t or q *\n");
printf("**************************************\n");
}

int read(char cmd)
{
int i,flag=0;
char choice[10]={'e','E','d','D','p','P','T','t','Q','q'};
for(i=0;i<10;i++)
{
if(cmd==choice[i]) flag++;
}
if(flag==1) return FALSE;
else return TRUE;
}
void ReadCommand(char &cmd) // 读入操作命令
{
do
{
cmd=getchar();
}
while(read(cmd));
}
void Interpret(char cmd) //解释执行操作命令
{
switch(cmd)
{
case 'e':case'E':
EnCoding();
Initialization();
break;
case 'd':case'D':
Decoding();
Initialization();
break;
case 'p':case'P':
PrintCodeFile();
Initialization();
break;
case't':case'T':
PrintTree(); // Print();
Initialization();
break;
case 'q': case'Q': exit(0);
break;
default: printf("Error\n");break;
}
}
void main() //用户驱式
{
char cmd;
Initialization(); //初始化
do
{
ReadCommand(cmd); //读入一个操作命令符
Interpret(cmd); //解释执行操作命令符
}
while(cmd!='q'&&cmd!='Q');
EnCoding();
Decoding();

}

3. 哈夫曼编码/译码器

注释非常详细,希望对你有所帮助!
#ifndef Huffman_Tree_h
#define Huffman_Tree_h
#endif

#include <stdio.h>

typedef struct {
unsigned int weight;
unsigned int parent,lchild,rchild;
}HTNode, * HuffmanTree; //存储赫夫曼树的结点类型

typedef char * * HuffmanCode; //用于存储字符集中各个字符相应的赫夫曼编码

void strcpy(char *S1,char *S2){ //将字符串S2复制到S1
int i = 0;
while( S2[i] != '\0' ){
S1[i] = S2[i];
i++;
}
S1[i] = '\0';
}

void Select(HuffmanTree HT,int t,int &s1,int &s2){ //在HT[1]到HT[t-1]中找出权值最小的两个S1和S2
int i = 1;
s1 = s2 = 0;
HT[0].weight = 65535;
while( i <= t ){ //遍历查找权值最小的结点S1
if( HT[i].parent == 0 && HT[i].weight < HT[s1].weight )
s1 = i;
i++;
}
i = 1;
while( i <= t ){ //遍历查找除S1外权值最小的结点S2
if( i != s1 && HT[i].parent == 0 && HT[i].weight < HT[s2].weight )
s2 = i;
i++;
}
}

int HuffmanCoding( HuffmanTree &HT,HuffmanCode &HC,int *w,int n){ //根据各个字符的权值构造赫夫曼树HT,将对应的赫夫曼编码存储在HC中
int s1,s2,m,i,start;
unsigned int c,f;
HTNode * p;
char *cd;
if( n <= 1 ) return 0;
m = 2 * n - 1; //赫夫曼树的总结点树为m
HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode)); //申请存储赫夫曼树的空间
for(p = HT + 1, i = 1; i <= n; ++i, ++p, ++w){ //将各个叶子结点的weight赋以相应的权值,parent,lchild,rchild均赋为0
p->weight = *(w+1);
p->parent = p->lchild = p->rchild = 0;
}
for( ; i <= m; ++i, ++p ){ //将各个非叶子结点的weight,parent,lchild,rchild均赋为0
p->weight = p->parent = p->lchild = p->rchild = 0;
}
for( i = n + 1; i <= m; ++i ){ //构造赫夫曼树,给各个非叶子结点赋值
Select(HT, i - 1, s1, s2);
HT[s1].parent = i; HT[s2].parent = i;
HT[i].lchild = s1; HT[i].rchild = s2;
HT[i].weight = HT[s1].weight + HT[s2].weight;
}
HC = (HuffmanCode)malloc((n + 1) * sizeof(char *)); //申请空间,用于存储指向存储各个字符相应赫夫曼编码的字符数组的指针
cd = (char *)malloc(n * sizeof(char)); //申请用于求赫夫曼编码
cd[n - 1] = '\0'; //编码结束符
for( i = 1; i <= n; ++i){ //逐个字符求赫夫曼编码
start = n -1; //编码在数组cd[]中的最前位置
for(c = i,f = HT[i].parent; f != 0; c = f, f = HT[f].parent) //从叶子到根逆向求编码
if(HT[f].lchild == c)
cd[ --start ] = '0';
else
cd[ --start ] = '1';
HC[i] = (char *)malloc((n - start)*sizeof(char)); //为第i个字符编码分配空间
strcpy(HC[i], &cd[start]); //将cd[]数组的start位置到n-1位置复制给HC[i]
}
free(cd); //释放空间
return 1;
}
以上为第一部分

#include <stdio.h>
#include <stdlib.h>
#include "Huffman_Tree.h"
#define Yes 1 //当程序已经调用过初始化赫夫曼树的InitHuff_T()函数,或已从htfTree文件读取过,则将Init_Mode置为Yes,否则为No
#define No 0

void InitHuff_T( HuffmanTree &HT, HuffmanCode &HC, char ch[],int &n ){ //初始化赫夫曼数,要求用户输入字符和相应权值
int i = 1,w[100],tem,j;
char a[20];
FILE *save;
printf("请输入编码字符集的大小n:");
scanf("%d",&n); //获取用户输入的字符集个数
while( i <= n ){ //获取用户输入的字符和相应权值,分别存储在ch[]和w[]数组中
printf("请输入第%d个字符和该字符的权值w:",i);
fflush(stdin);
scanf("%c%d",&ch[i],&w[i]);
i++;
}
ch[i] = '\0';
HuffmanCoding(HT,HC,w,n); //根据用户的输入,生成赫夫曼数及各个字符相应的赫夫曼编码,分别存在HT树和HC中
if(( save = fopen("htfTree","w")) == NULL ){ //打开用于存储赫夫曼树的文件
printf("Open file fail......\n");
exit(0);
}
tem = n; //接下来的14行是将字符集大小转换成字符形式写入到文件中
j = 0;
while( tem != 0 ){
tem = tem / 10;
j++;
}
tem = n;
a[j] = '\0';
while( tem != 0 ){
a[j - 1] = (char)(tem % 10 + 48);
tem = tem / 10;
j--;
}
fputs(a,save);
printf("%d\n",n); //向屏幕输出字符集大小n
fputc('\n',save);
for( i = 1; i <= n; i++ ){ //分别向文件和屏幕输出各个字符和相应的赫夫曼编码
fputc(ch[i],save); printf("%c\t",ch[i]);
fputc('\t',save);
fputs(HC[i],save); printf("%s\n",HC[i]);
fputc('\n',save);
}
for(i = 1; i <= 2 * n - 1; i++ ){ //将赫夫曼树各个结点的parent,lchild,rchild分别写入到文件中
tem = HT[i].parent; //将i结点的parent转换成字符并写入到文件中
if(tem == 0){
fputc(tem + 48,save);
fputc(' ',save);
}
else{
j = 0;
while( tem != 0 ){
tem = tem / 10;
j++;
}
tem = HT[i].parent;
a[j] = '\0';
while( tem != 0 ){
a[j - 1] = (char)(tem % 10 + 48);
tem = tem / 10;
j--;
}
fputs(a,save);
fputc(' ',save);
}

tem = HT[i].lchild; //将i结点的lchild转换成字符并写入到文件中
if(tem == 0){
fputc(tem + 48,save);
fputc(' ',save);
}
else{
j = 0;
while( tem != 0 ){
tem = tem / 10;
j++;
}
tem = HT[i].lchild;
a[j] = '\0';
while( tem != 0 ){
a[j - 1] = (char)(tem % 10 + 48);
tem = tem / 10;
j--;
}
fputs(a,save);
fputc(' ',save);
}

tem = HT[i].rchild; //将i结点的rchild转换成字符并写入到文件中
if(tem == 0){
fputc(tem + 48,save);
fputc('\n',save);
}
else{
j = 0;
while( tem != 0 ){
tem = tem / 10;
j++;
}
tem = HT[i].rchild;
a[j] = '\0';
while( tem != 0 ){
a[j - 1] = (char)(tem % 10 + 48);
tem = tem / 10;
j--;
}
fputs(a,save);
fputc('\n',save);
}
}
fclose(save);
}

void Encoding(HuffmanTree &HT, HuffmanCode &HC, char ch[]){ //根据赫夫曼编码将用户指定的文件中的字符编成相应的编码,并将所得编码存储到用户指定文件
FILE *ToBeTran,*CodeFile;
char ToBeTran_Name[100],CodeFile_Name[100]; //存储用户指定文件的文件名
int i;
char c;
printf("请输入所要进行编码的文件的文件名:");
scanf("%s",ToBeTran_Name); //获得所要进行编码的文件的文件名
if(( ToBeTran = fopen(ToBeTran_Name,"r")) == NULL ){ //打开文件
printf("Open file fail......\n");
exit(0);
}
printf("请输入编码后编码表示的信息所存储到的文件的文件名:");
scanf("%s",CodeFile_Name); //获得编码后编码表示的信息所存储到的文件的文件名
if(( CodeFile = fopen(CodeFile_Name,"w")) == NULL ){ //打开文件
printf("Open file fail......\n");
exit(0);
}
c = fgetc(ToBeTran); //从文件读取一个字符
while( c != EOF ){ //对文件中的各个字符进行编码,直至文件结尾
i = 1;
while( c != ch[i] && ch[i] != '\0' ) //在ch[]数组中查找从文件读取的字符
i++;
if(ch[i] == '\0'){ //未找到,c不在ch[]数组中,c无法被识别,程序出错,退出
printf("字符%c无法识别,程序将退出。\n",c);
exit(0);
}
fputs(HC[i],CodeFile); //若找到,则将c相应的赫夫曼编码写入到文件中
printf("%s",HC[i]); //将c相应的赫夫曼编码输出到屏幕
c = fgetc(ToBeTran); //读入文件中的下一个字符
}
printf("\n");
fclose(ToBeTran);
fclose(CodeFile);
}

void Decoding(HuffmanTree HT, char ch[] , int n){ //对指定的存储由赫夫曼编码表示的信息的文件进行译码,翻译成相应的字符表示,并存储到指定文件
int p,i = 1;
char code[1000],c;
char CodeFile_Name[100],TextFile_Name[100]; //存储用户指定文件的文件名
p = 2 * n - 1;
FILE *CodeFile,*TextFile;
printf("请输入所要译的文件名:");
scanf("%s",CodeFile_Name); //获得所要译的文件的文件名
if(( CodeFile = fopen("CodeFile","r")) == NULL ){ //打开文件
printf("Open file fail......\n");
exit(0);
}
printf("请输入译后的字符存储到的文件的文件名:");
scanf("%s",TextFile_Name); //获得译后的字符存储到的文件的文件名
if(( TextFile = fopen(TextFile_Name,"w")) == NULL ){ //打开文件
printf("Open file fail......\n");
exit(0);
}
c = fgetc(CodeFile);
while( c != EOF ){
code[i] = c;
i++;
c = fgetc(CodeFile);
}
code[i] = '\0'; //从文件读取字符,存储在code[]数组中
i = 1;
while ( code[i] != '\0' && p != 0 ){ //对数组code[]中的赫夫曼编码进行译码
if ( code[i] == '0' )
p=HT[p].lchild; //进入左分支
else
p = HT[p].rchild; //进入右分支
if (!HT[p].lchild&& !HT[p].rchild){ //进入叶子结点
fputc(ch[p], TextFile); //将相应的字符写入到文件中
printf("%c",ch[p]); //将相应的字符输出到屏幕
p = 2 * n - 1; //重新从树根出发进行译码
}
i++;
}
printf("\n");
}

void ReadHuff_T( HuffmanTree &HT, HuffmanCode &HC, char ch[], int &n){ //从文件读取赫夫曼树
FILE *htfTree;
char c[100],ch1;
int i,j,t;
if(( htfTree = fopen("htfTree","r")) == NULL ){ //打开存有赫夫曼树信息的文件
printf("Open file fail......\n");
exit(0);
}
fgets(c,10,htfTree); //获取赫夫曼树叶子结点个数的字符串表示形式
i = 0; //以下6行将字符串形式转换成整数形式
while( c[i] != '\n' )
i++;
n = 0;
for( j = 0; j < i; j++ )
n = 10 * n + c[j] - '0'; //求出叶子结点数n
HC = (HuffmanCode)malloc((n + 1) * sizeof(char *)); //申请HC空间
HT = (HuffmanTree)malloc((2 * n) * sizeof(HTNode)); //申请赫夫曼树存储空间
i = 1;
while( i <= n ){
ch[i] = fgetc(htfTree); //读取字符集中的一个字符
HC[i] = (char *)malloc((10)*sizeof(char)); //申请用于存储读取到的字符集中的字符的赫夫曼编码的空间
fgetc(htfTree); //将‘\t’输出
ch1 = fgetc(htfTree); //读取赫夫曼编码,存储在相应的HC[i][]数组里
int j = 0;
while( ch1 != '\n' ){
HC[i][j] = ch1;
j++;
ch1 = fgetc(htfTree);
}
HC[i][j] = '\0';
i++;
}
ch[i] = '\0';
i = 0;
while( i < 2 * n - 1 ){ //读取赫夫曼树的各个结点的parent,lchild,rchild.并赋值到赫夫曼树HT中
ch1 = fgetc(htfTree); //读取parent的字符串形式,存储在c[]中,并将其转换成整数形式,赋给HT[i].parent
j = 0;
while( ch1 != ' ' ){
c[j] = ch1;
j++;
ch1 = fgetc(htfTree);
}
HT[i+1].parent = 0;
for( t = 0; t < j; t++ )
HT[i+1].parent = 10 * HT[i+1].parent + c[t] - '0';
ch1 = fgetc(htfTree); //读取lchild的字符串形式,并将其转换成整数形式,赋给HT[i].lchild
j = 0;
while( ch1 != ' ' ){
c[j] = ch1;
j++;
ch1 = fgetc(htfTree);
}
HT[i+1].lchild = 0;
for( t = 0; t < j; t++ )
HT[i+1].lchild = 10 * HT[i+1].lchild + c[t] - '0';
ch1 = fgetc(htfTree); //读取rchild的字符串形式,并将其转换成整数形式,赋给HT[i].rchild
j = 0;
while( ch1 != '\n' ){
c[j] = ch1;
j++;
ch1 = fgetc(htfTree);
}
HT[i+1].rchild = 0;
for( t = 0; t < j; t++ )
HT[i+1].rchild = 10 * HT[i+1].rchild + c[t] - '0';
i++;
}
}

int main(){
HuffmanTree HT;
HuffmanCode HC;
char ch[100]; //用于存储字符集
int n,Init_Mode = No; //n为字符集的大小,Init_Mode = No 表示内存中没有赫夫曼树的信息
char mode; //让用户选择不同的操作
printf("请输入你要选择的功能\n");
printf("\t\tI -- 初始化\t\tE -- 编码\n");
printf("\t\tD -- 译码 \t\tQ -- 退出程序\n");
scanf("%c",&mode); //获得用户选择的操作
while( mode != 'Q' && mode != 'q' ){ //当用户输入不为Q或q时,执行相应操作
switch(mode){
case 'I' :
InitHuff_T(HT,HC,ch,n);
Init_Mode = Yes;
break;
case 'i' :
InitHuff_T(HT,HC,ch,n);
Init_Mode = Yes;
break;
case 'E' :
if( No == Init_Mode )
ReadHuff_T(HT,HC,ch,n);
Encoding(HT,HC,ch);
Init_Mode = Yes;
break;
case 'e' :
if( No == Init_Mode )
ReadHuff_T(HT,HC,ch,n);
Encoding(HT,HC,ch);
Init_Mode = Yes;
break;
case 'D' :
if( No == Init_Mode )
ReadHuff_T(HT,HC,ch,n);
Decoding(HT,ch,n);
Init_Mode = Yes;
break;
case 'd' :
if( No == Init_Mode )
ReadHuff_T(HT,HC,ch,n);
Decoding(HT,ch,n);
Init_Mode = Yes;
default :
printf("您的输入有错,请重新选择.\n");
}
printf("请输入你要选择的功能\n");
printf("\tI -- 初始化\tE -- 编码\n");
printf("\tD -- 译码 \tQ -- 退出程序\n");
fflush(stdin);
scanf("%c",&mode); //让用户继续选择相应的操作,直至用户选择退出
}
return 0;
}

4. 哈夫曼编、译码器

这个是我课程设计弄的,也是哈弗曼编码译码器
#include<iostream>
#include<stdlib.h>
#include<string.h>
using namespace std;

typedef struct{
int weight;
int parent,lchild,rchild;
int asc;
}HTNode,*HuffmanTree; //定义赫夫曼存储结构

struct node{
int ASCII;
int n;
};
struct node a[127];
struct node w[127];
//一些全局变量
int count;
HTNode H_T[250];
char ** HC;
char filename[20];

//函数声明
void menu1(); //菜单1
HuffmanTree HeapSort(HuffmanTree HT,int length); //堆排序
void MinHeapify(HuffmanTree HT, int k,int len); //调整成一个小顶堆
void buildMinHeap(HuffmanTree HT,int len); //建一个小顶堆
void swap(HTNode &t1,HTNode &t2); //交换两结构体
void savefile(); //把输入的英文文章保存到文件
void loadfile(); //从文件中读取文章
HuffmanTree CreateHuffman(HuffmanTree &HT,struct node *w,int n); //建立赫夫曼数并存入文件
void BianMa(HuffmanTree HT,int n ); //字符编码
void BianMa_all(HuffmanTree HT,char**HC,char *filename); //整篇文章编码
int loadfile2(); //从文件读入文章
void JieMa(); //解码

//主函数
int main()
{
char s;
while(s!='0')
{
system("cls");
cout<<"\n\n\n";
cout<<"\t\t\t\t赫夫曼编码/译码器"<<endl<<endl<<endl<<endl<<endl;
cout<<"\t\t\t\t 1.编码"<<endl<<endl<<endl<<endl;
cout<<"\t\t\t\t 2.译码"<<endl<<endl<<endl<<endl;
cout<<"\t\t\t\t 0.退出"<<endl<<endl<<endl<<endl;
cout<<"\t请输入0—2进行选择,按回车确认";
cin>>s;
switch(s)
{
case '1': menu1(); break;
case '2':
{
system("cls");
JieMa();
system("pause");
break;
}

}

}
}

//菜单1
void menu1(){
char s;
int i;
int a;
char c;
char fpname[20]="article.txt";
HuffmanTree HT;
while(s!='0'){

system("cls");
cout<<"\n\t\t\t\t编码界面";
cout<<"\n\n\n\t\t\t\t1.输入英文文章"<<endl;
cout<<"\n\n\t\t\t\t2.从文件中读入文章"<<endl;
cout<<"\n\n\t\t\t\t0.返回上一层"<<endl;
cout<<"\n\t请输入0—2进行选择,按回车确认";
cin>>s;
switch(s){
case'1':
system("cls");
savefile();
loadfile();
CreateHuffman(HT,w,count);
BianMa(HT,count);
BianMa_all(HT,HC,fpname);
system("cls");
cout<<"出现字符种类共计:";
cout<<count<<endl;
for(i=1;i<=count;i++)
{ a=HT[i].asc;
c=(char)a;

cout<<"________________________________________________________________________________"<<endl;
cout<<"\t\t\t字符:";
cout<<c<<endl;
cout<<"\t\t\tASCII码:";
cout<<a<<endl;
cout<<"\t\t\t频数:";
cout<<HT[i].weight<<endl;
cout<<"\t\t\t赫夫曼编码:";
cout<<HC[i]<<endl;

}
cout<<"________________________________________________________________________________";
cout<<"\n\t\t整篇文章的编码已存入文件“赫夫曼编码.txt”"<<endl;

system("pause");
break;

case'2':
system("cls");
if(loadfile2())
{ system("pause");
return;}
CreateHuffman(HT,w,count);
BianMa(HT,count);
BianMa_all(HT,HC,filename);
system("cls");
cout<<"出现字符种类共计:";
cout<<count<<endl;
for(i=1;i<=count;i++)
{ a=HT[i].asc;
c=(char)a;

cout<<"________________________________________________________________________________"<<endl;
cout<<"\t\t\t字符:";
cout<<c<<endl;
cout<<"\t\t\tASCII码:";
cout<<a<<endl;
cout<<"\t\t\t频数:";
cout<<HT[i].weight<<endl;
cout<<"\t\t\t赫夫曼编码:";
cout<<HC[i]<<endl;

}
cout<<"________________________________________________________________________________";
cout<<"\n\t\t整篇文章的编码已存入文件“赫夫曼编码.txt”"<<endl;
system("pause");
break;
}

}

}

//交换结构体
void swap(HTNode &t1,HTNode &t2)
{
HTNode m;

m = t1;
t1 = t2;
t2 = m;
}

//从键盘输入文章并保存
void savefile(){

FILE *fp;
char article;
if((fp=fopen("article.txt","w"))==NULL){

printf("打开文件不成功!");
exit(0);
}
cout<<"请输入英文文章,以#结束:";
getchar();
article=getchar();
while(article!='#'){

fputc(article,fp);

article=getchar();
}
fclose(fp);
}

//从文件读取文章,并统计字符出现频数
void loadfile(){

FILE *fp;
char ch;
int i,k,j=0;
count=0;
for(i=0;i<=127;i++) //把所有字符的ascii码存在数组
{ a[i].ASCII=i;
a[i].n=0;

}
if((fp=fopen("article.txt","r"))==NULL){

printf("打开文件不成功!");
exit(0);
}
ch=fgetc(fp);
k=(int)ch;
a[k].n++;
while(!feof(fp)){
ch=fgetc(fp);
k=(int)ch;
a[k].n++;
}
fclose(fp);

for(i=0;i<=127;i++) //统计字符种类总数
{
ch=(char)i;
if(a[i].n){
count++;
}
}
for(i=0;i<=127;i++)
{
for(;j<count;)
{
if(a[i].n)
{
w[j].n=a[i].n;
w[j].ASCII=a[i].ASCII;
j++;
break;
}
else break;
}
}

}

//调整为小顶堆
void MinHeapify(HuffmanTree HT, int k,int len)
{
int left=k*2;
int right=k*2+1;
int large;
int l=len;

large = k;
if (left<=l&&HT[left].weight<HT[large].weight)
large = left;

if (right<=l&& HT[right].weight<HT[large].weight)
large=right;

if (large!=k)
{
swap(HT[k],HT[large]);
MinHeapify(HT,large,l);
}
}

//建立小顶堆
void buildMinHeap(HuffmanTree HT,int len)
{
int i;
for (i=len/2;i>=1;i--)
{
MinHeapify(HT,i,len);
}
}

//堆排序
HuffmanTree HeapSort(HuffmanTree HT,int length)
{
int i;
int l=length;
buildMinHeap(HT,length);
for (i=length;i>= 2;i--)
{
swap(HT[1],HT[i]);
length--;
MinHeapify(HT,1,length);
}

return HT;
}

//建立赫夫曼数
HuffmanTree CreateHuffman(HuffmanTree &HT,struct node *w,int n)
{
int i,m,s1,s2,k1,k2,j,x,a;
FILE *fp,*fp2;

if(n<=1) return HT;
m=2*n-1;
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//0不用

for(i=1,j=0;i<=n;i++,j++)
{ HT[i].asc=w[j].ASCII;
HT[i].weight=w[j].n;
HT[i].parent=0;
HT[i].lchild=0;
HT[i].rchild=0;
}
for(;i<=m;i++)
{ a=250+i;
HT[i].asc=a;//父亲节点的asc可以是大于127的任意值
HT[i].weight=0;
HT[i].parent=0;
HT[i].lchild=0;
HT[i].rchild=0;
}
for(i=1;i<=n;i++){

H_T[i].asc=HT[i].asc;
H_T[i].parent=HT[i].parent;
H_T[i].lchild=HT[i].lchild;
H_T[i].rchild=HT[i].rchild;
H_T[i].weight=HT[i].weight;
}

for(i=n+1,x=n;i<=m;i++,x--)
{

HeapSort(H_T,x);
k1=H_T[x].asc;
k2=H_T[x-1].asc;
for(j=1;j<=127;j++)
{
if(HT[j].asc==k1)

}

for(j=1;j<=127;j++)
{
if(HT[j].asc==k2)

}

HT[s2].parent=i;
HT[s1].parent=i;
HT[i].lchild=s1;
HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;

H_T[x-1].asc=HT[i].asc;
H_T[x-1].lchild=HT[i].lchild;
H_T[x-1].parent=HT[i].parent;
H_T[x-1].rchild=HT[i].rchild;
H_T[x-1].weight=HT[i].weight;

}
if((fp2=fopen("count.txt","w"))==NULL) //保存赫夫曼树
{
cout<<"文件打开不成功!"<<endl;
exit(0);
}
fputc(count,fp2);
if((fp=fopen("HuffmanTree.dat","wb"))==NULL)
{ cout<<"文件打开不成功!"<<endl;
exit(0);

}

for(i=1;i<=(2*count-1);i++){
fwrite(&HT[i],sizeof(HTNode),1,fp);
}
fclose(fp);
fclose(fp2);
return HT;

}

//逆向编码
void BianMa(HuffmanTree HT,int n){
char *cd,temp;

int c,f,i,j,len,p,q;

cd=(char *)malloc(n*sizeof(char));
HC=(char * *)malloc(n*sizeof(char*));
for(i=1;i<=n;i++){
for(c=i,f=HT[i].parent,j=0;f!=0;c=f,f=HT[f].parent,j++)
{ if(HT[f].lchild==c) cd[j]='0';
else cd[j]='1';
if(HT[f].parent==0)
cd[j+1]='\0';

}

len=strlen(cd);
for(p=0,q=len-1;p<=q;p++,q--)
{
temp=cd[q];
cd[q]=cd[p];
cd[p]=temp;
}
cd[len]='\0';
HC[i]=(char*)malloc((len+10)*sizeof(char));
strcpy(HC[i],cd);

}

}

//整篇文章编码,并存入文件
void BianMa_all(HuffmanTree HT,char**HC,char *filename){
char ch;
int k,i;
FILE *fp,*fp2;

char code[100];
if((fp=fopen(filename,"r"))==NULL){

printf("打开文件不成功!");
exit(0);
}
if((fp2=fopen("赫夫曼编码.txt","w"))==NULL){

printf("打开文件不成功!");
exit(0);
}
ch=fgetc(fp);
k=(int)ch;
while(!feof(fp))
{

for(i=1;i<=count;i++)
{
if(k==HT[i].asc)
strcpy(code,HC[i]);

}
fputs(code,fp2);
ch=fgetc(fp);
k=(int)ch;

}
fclose(fp);
fclose(fp2);

}

void JieMa(){
int i,k,a,t,n=0;
FILE *fp1,*fp2,*fp3;
char ch,c;
HuffmanTree ht;
if((fp3=fopen("count.txt","r"))==NULL) //从文件读出字符总数
{
printf("打开文件不成功!");
exit(0);
}
n=fgetc(fp3);
ht=(HuffmanTree)malloc(2*n*sizeof(HTNode));
if((fp1=fopen("赫夫曼编码.txt","r"))==NULL)
{

printf("打开文件不成功!");
exit(0);
}

if((fp2=fopen("HuffmanTree.dat","rb"))==NULL)
{ cout<<"文件打开不成功!"<<endl;
exit(0);

}
for(i=1;i<=2*n-1;i++)

fread(&ht[i],sizeof(HTNode),1,fp2);

for(i=1;i<=2*n-1;i++)
{
if(ht[i].parent==0)
}

ch=fgetc(fp1);
while(!feof(fp1)){
if(ch=='0')
{
k=ht[k].lchild;
if(ht[k].lchild==0)
{a=ht[k].asc;
c=(char)a;
printf("%c",c);;

k=t;
}
}
if(ch=='1')
{
k=ht[k].rchild;
if(ht[k].lchild==0)
{ a=ht[k].asc;
c=(char)a;
printf("%c",c);

k=t;
}

}

ch=fgetc(fp1);
}
fclose(fp1);
fclose(fp2);

}

//读取文件中的文章,可自己选择文件
int loadfile2(){

FILE *fp;
char ch;
int i,k,j=0;
count=0;
for(i=0;i<=127;i++)
{ a[i].ASCII=i;
a[i].n=0;

}
cout<<"\n\n\n\t\t\t请输入你要打开的文件名:";
cin>>filename;
if((fp=fopen(filename,"r"))==NULL){

printf("打开文件不成功!");
return 1;
}
ch=fgetc(fp);
k=(int)ch;
a[k].n++;
while(!feof(fp)){
ch=fgetc(fp);
k=(int)ch;
a[k].n++;
}
fclose(fp);

for(i=0;i<=127;i++){
ch=(char)i;
if(a[i].n){
count++;
}
}
for(i=0;i<=127;i++)
{
for(;j<count;)
{
if(a[i].n)
{
w[j].n=a[i].n;
w[j].ASCII=a[i].ASCII;
j++;
break;
}
else break;
}
}
return 0;
}

5. 哈夫曼编码和译码

class HaffmanNode //哈夫曼树的结点类
{
int weight; //权值老孝
int parent,left,right; //父母结点和左右孩子下标

public HaffmanNode(int weight)
{
this.weight = weight;
this.parent=-1;
this.left=-1;
this.right=-1;
}
public HaffmanNode()
{
this(0);
}
public String toString()
{
return this.weight+", "+this.parent+", "+this.left+", "+this.right;
}
return code;
}

public static void main(String[] args)
{
int[] weight={5,29,7,8,14,23,3,11}; /尘侍/指定权值集合
HaffmanTree htree = new HaffmanTree(weight);
System.out.println("哈夫曼树的结点数组:\n"+htree.toString());
String[] code = htree.haffmanCode();
System.out.println("哈夫曼编码:");
for (int i=0; i<code.length; i++)
System.out.println(code[i]);
}
}
希望能解决您的问题。派含吵

6. 哈夫曼编码与译码

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
#include <conio.h>
#define NN 10000
#define M 2*NN-1
#define IN 0
#define OUT 1
#define MAX_INT 32767
#define PRINTLN printf("\n\n\n\n\n\n\n\n");

typedef struct
{
int wi;
char c;
int tag;
int parent, lchild, rchild;
}huffmtype;

typedef char* encodetype[NN+1];

typedef struct
{
char c;
int times;
}codetype;

void PRINT()
{
PRINTLN;
printf("\t\t\t Huffman编/译码器\n");
printf("\t\t\t ====================\n");
printf("\t\t\t 1.编码 2.译码 3.退出\n\n");
printf("\t\t\t >>选择:");
}

FILE* OpenFile(char filename[20], char type[3])
{
FILE *fp = NULL;

if((fp = fopen(filename, type)) == NULL) exit(1);

return fp;
}

int ReadCode(codetype* code, FILE* fp)
{
char c;//保存某次从文件中读入字符-
int n = 1;//记录首次出现字符在数组中的下标-
int i;//循环变量-
int cnt = 1;
int tag;//标志某次读入字符是否为首次出现字符,tag=1表示是首次出现;tag=0表示本次读入字符为已有字符

while((c = fgetc(fp)) != EOF)//当文件没有结束时读入字符-
{
//从fp指向文件中读取字符,存入字符变量c中-
tag = 1;//假设本次读取字符为首次出现字符-
for(i = 1; i < n; i++)
{
if(c == code[i].c)//如果本次读入字符为存储在下标为i已有字符-
{
code[i].times++;//权值加1-
tag = 0;//标记本字符为已有字符-
break;//在已有数组元素中找到本次读入字符,结束for(;;)循环-
}
}

if(tag)//当本字符为首次出现字符时-
{
code[n].c = c;//把改字符存入n指向的数组单元中-
code[n].times = 1;//记字符出现次数为1-
n++;//n指向下一个数组地址-
}
}

return n - 1;//返回文件中字符集合的元素个数-

}

void InitHuffmanTree(huffmtype* huffmtree, int real_n, int real_m)//初始化-
{
int i;

for(i = real_n; i <= real_m; i++)
{
huffmtree[i].wi = 0;
huffmtree[i].c = 0;
huffmtree[i].tag = IN;
huffmtree[i].lchild = huffmtree[i].rchild = huffmtree[i].parent = 0;
}
}

void ReadDataWeight_Init(huffmtype* huffmtree, codetype* code, int real_n)//获取权值及数值域值-
{
int i;

for(i = 1; i <= real_n; i++)//-
{
huffmtree[i].wi = code[i].times;
huffmtree[i].c = code[i].c;
huffmtree[i].tag = IN;
huffmtree[i].lchild = huffmtree[i].rchild = huffmtree[i].parent = 0;
}
}

int LeastNode(huffmtype *huffmtree, int max_i)//找到最小权值节点地址-
{
int i;
int least_i;
int max = MAX_INT;

for(i = 1; i <= max_i; i++)//遍历1到max_i节点-
{
if(huffmtree[i].wi < max && huffmtree[i].tag == IN)//若节点权值比max小并且在森林中-
{
max = huffmtree[i].wi;//刷新max值-
least_i = i;//保存当前节点地址-
}
}

huffmtree[least_i].tag = OUT;//将最小权值节点从森林中移除-

return least_i;//返回最小节点地址
}

void Slect(huffmtype *huffmtree, int max_i, int *x1, int *x2)//找到权值最小的两个节点,并将其下标值保存在x1,x2中-
{
*x1 = LeastNode(huffmtree, max_i);//计算合法最下权值下标-
*x2 = LeastNode(huffmtree, max_i);//
}

void CreatHuffmanTree(huffmtype* huffmtree, int real_n, int real_m)//创建哈弗曼树-
{
int i;
int x1, x2;

for(i = real_n + 1; i <= real_m; i++)
{
Slect(huffmtree, i-1, &x1, &x2);//找到权值最小的两个节点,并将其下标值保存在x1,x2中-
huffmtree[i].wi = huffmtree[x1].wi + huffmtree[x2].wi;//计算双气节点权值-
huffmtree[x1].parent = huffmtree[x2].parent = i;//计算双亲节点地址-
huffmtree[i].lchild = x1; huffmtree[i].rchild = x2;//计算双亲节点左右孩子地址-
}
}

void Encode(huffmtype *huffmtree, encodetype encode, int real_n)//依据已创建的HuffmanTree对字符进行编码-
{

char *cd;

int i;

int start;

int c, p;

cd = (char*)malloc(real_n*sizeof(char));//cd用来存放某次运行时当前字符编码-

cd[real_n - 1] = '\0';//作为字符结束符-

for(i = 1; i <= real_n; i++)//对real_n个节点进行遍历-

{

start = real_n-1;

c = i;//c保存当前节点地址(下标)-

p = huffmtree[i].parent;//p保存当前节点双亲地址-

while(p)

{

start--;//计算编码的起始地址-

if(huffmtree[p].lchild == c)//若当前节点为其双亲的左孩子-

{

cd[start] = '0';//编码为0-

}

else//若为右孩子-

{

cd[start] = '1';//编码为1-

}

c = p;//节点前进-

p = huffmtree[p].parent;//计算前进后节点双亲节点地址-

}

encode[i] =(char*)malloc((real_n - start)*sizeof(char));//申请空间用于存放编码-

strcpy(encode[i], &cd[start]);//将本次编码存入encode数组中-

}

free(cd);//释放闲置存储空间-

}

void WriteToFile(FILE *fp, encodetype encode, codetype *code, int real_n, char *readfile)//将编码输出到文件

{

int i;

char cod[NN];

FILE *fp2;

char c;

int cnt = 1, j;

fp2 = fopen(readfile, "rt");

while((c = fgetc(fp2)) != EOF)

{

cod[cnt++] = c;

}

fclose(fp2);

for(i = 1; i < cnt; i++)

{

for(j = 1; j <=real_n; j++)

{

if(cod[i] == code[j].c)

{

break;

}

}

fprintf(fp, "%s", encode[j]);

}

fclose(fp);

}

int IsError(FILE *fp)//对打开文件进行出错判断-

{

if(!fp)

{

printf("\t\t\t ×打开文件错误\n");

printf("\t\t\t 任意键返回主菜单");

getch();

return 1;//文件打开失败-

}

return 0;//文件打开成功-

}

void GetFilename(char *filename, char type[13])//得到用户输入相关文件名

{

system("cls");

PRINTLN;

printf("\t\t\t %s:", type);

fflush(stdin);

gets(filename);

}

int PutIntoCode(codetype code[], huffmtype huffmtree[])//编码函数

{

encodetype encode;

FILE* fp;//文件类型指针-

int real_n;//用来存放字符集长度-

char readfile[20];//从readfile文件中读取字符,写入到writefile文件中-

GetFilename(readfile, "读取源文件");//从键盘读取文件名-

fp=OpenFile(readfile, "rt");//打开待编码文件-

if(IsError(fp))//判断是否正确打开文件-

{

return 0;//打开文件失败,返回主菜单-

}

real_n=ReadCode(code, fp);//从readfile文件读取字符,将字符集合元素存入code数组,将集合元素个数存入real_n-

fclose(fp);//关闭文件-

ReadDataWeight_Init(huffmtree, code, real_n);//初始化HuffmanTree中从1到real_n的元素-

InitHuffmanTree(huffmtree, real_n, 2*real_n-1);//初始化HuffmanTree中real_n到2*real_n的元素-

CreatHuffmanTree(huffmtree, real_n, 2 * real_n - 1);//创建HuffmanTree-

Encode(huffmtree, encode, real_n);//根据HuffmanTree对字符进行编码,编码结果保存到encode数组中-

fp = OpenFile("CodeFile.txt", "wb");//打开待写入文件-

WriteToFile(fp, encode, code, real_n, readfile);//将encode数组中元素写入到文件中-

fclose(fp);//关闭文件-

printf("\t\t\t 完成编码并保存至CodeFile.txt文件中");//打印完成编码信息-

getch();//等待用户输入任意键返回主菜单-

return real_n;

}

void Translate(codetype code[], huffmtype huffmtree[], int real_n)//译码函数

{

FILE *fp,*fp2;

int i, real_m;

char c;

char writefile[20];

GetFilename(writefile, "保存解码文件到");

fp = OpenFile("CodeFile.txt", "rb");

fp2 = OpenFile(writefile, "wt");

if(IsError(fp))

{

return;

}

i = real_m = 2*real_n - 1;

while((c = fgetc(fp)) != EOF)

{

if(c == '0')

{

i = huffmtree[i].lchild;

}

else

{

i = huffmtree[i].rchild;

}

if(huffmtree[i].lchild == 0)
{
fputc(code[i].c, fp2);
i = real_m;
}
}

fclose(fp);
fclose(fp2);
printf("\t\t\t 完成译码任务");
getch();

}

int main(void)
{
int choice;
int real_n = 0;

codetype code[NN];
huffmtype huffmtree[NN];

while(1)
{
system("cls");
PRINT();

scanf("%d",&choice);
switch(choice)
{
case 1 :
real_n = PutIntoCode(code, huffmtree);
break;//编码函数
case 2 :
if(real_n) Translate(code, huffmtree, real_n);break;//译码函数
case 3 :
exit(1);//退出程序
default :
printf("\t\t\t ★无效输入");
getch();
break;
}
}

return 0;

}

7. 课程设计-哈夫曼编码/译码的设计与实现

哈哈~~~南工的同志??、、、、、、我也不会。

8. 利用 数据结构 实现 哈夫曼编码/译码实现

//D:\2010 代码\haffman\haffman\Node_statement.h
#define MAXVALUE 1000//定义最大权值
#define MAXBIT 100//定义哈夫曼树中叶子结点个数
typedef struct
{
char data;//字符值
int num;//某个值的字符出现的次数
}TotalNode;
//统计结点,包括字符种类和出现次数
typedef struct
{
TotalNode tot[300];//统计结点数组
int num;//统计数组中含有的字符个数
}Total;
//统计结构体,包括统计数组和字符种类数
typedef struct
{
char mes[300];//字符数组
int num;//总字符数
}Message;
//信息结构体,包括字符数组和总字符数
typedef struct{
int locked[500];//密码数组
int num;//密码总数
}Locking;
//哈夫曼编码后的密文信息
typedef struct
{
char data;//字符
int weight;//权值
int parent;//双亲结点在数组HuffNode[]中的序号
int lchild;//左孩子结点在数组HuffNode[]中的序号
int rchild;//右孩子结点在数组HuffNode[]中的序号
}HNodetype;
//哈夫曼树结点类型,包括左右孩子,权值和信息
typedef struct
{
int bit[MAXBIT];
int start;
}HCodetype;
//哈夫曼编码结构体,包括编码数组和起始位

void reading_file(Message *message);//从文件中读取信息
int writing_file(Message *message);//将信息写进文件
void total_message(Message *message,Total *total);//统计信息中各字符的次数
void HaffmanTree(Total *total,HNodetype HuffNode[]);//构建哈夫曼树
void HaffmanCode(HNodetype HuffNode[],HCodetype HuffCode[],Total *total);//建立哈夫曼编码
void writing_HCode(HNodetype HuffNode[],HCodetype HuffCode[],Total *total);//将编码规则写进文件
void lock(Message *message,HNodetype HuffNode[],HCodetype HuffCode[],Total *total,Locking *locking);//给文件信息加密编码
void writing_lock(Locking *locking);//将已编码信息写进文件
void first_function(HNodetype HuffNode[],HCodetype HuffCode[],Total *total,Message *message);
void display(Total *total,HNodetype HuffNode[]);
void writing_translate(Locking *locking,HCodetype HuffCode[],HNodetype HuffNode[],Total *total);//将已编码信息翻译过来并写进文

//D:\2010 代码\haffman\haffman\function_mian.cpp
#include"Node_statement.h"
#include<iostream>
#include<fstream>
#include "cstdlib"
using namespace std;
int main()
{
int i,j,choice,mark=0;//mark标记文件信息是否读入到内存中
HNodetype HuffNode[500];//保存哈夫曼树中各结点信息
HCodetype HuffCode[300];
Locking *locking;
Total *total;
Message *message;
locking=new Locking;
locking->num=0;
total=new Total;
total->num=0;
message=new Message;
message->num=0;
//初始化变量
printf("┏ ┓\n");
printf("┣ haffman_code system ┫ \n");
printf("┗ ┛\n");
printf("\n\n");
choice=0;
while(choice!=7 )
{

printf("#〓§〓〓〓〓〓§〓〓〓〓§〓〓〓〓§〓# \n ");
printf(" 0:go \n");
printf("※********** 1:从文件读取信息**********************※\n");
printf(" *********** 2:显示编码规则 ********************* \n");
printf(" ********** 3:将原文件信息写进文件 ************ \n");
printf(" ********* 4:将编码规则写进文件 ************ \n");
printf(" ********** 5:将编码后的信息写进文件 ********** \n");
printf(" *********** 6:将译码后的信息写进文件 *********\n");
printf("※***********7:退出 *****************************※\n");
printf("#〓§〓〓〓〓〓§〓〓〓〓§〓〓〓〓§〓# \n ");
printf(" please input the choice ");
cin>>choice;
switch(choice)
{
case 1:
reading_file(message);//从文件中读取信息
mark=1;
break;
case 2://显示编码规则
if(mark==0)cout<<"请先从文件中读取信息!"<<endl;
else
{
first_function(HuffNode,HuffCode,total,message);
cout<<"编码规则为"<<endl;
for(i=0;i<total->num;i++)//显示编码规则
{
cout<<total->tot[i].data<<" ";
for(j=HuffCode[i].start+1;j<total->num;j++)
cout<<HuffCode[i].bit[j];
cout<<endl;
}
}
break;
case 3://将原文件信息写进文件a_test1.txt
if(mark==0)cout<<"请先从文件中读取信息!"<<endl;
else

writing_file(message);//将信息写进文件
break;
case 4://将编码规则写进文件
if(mark==0)cout<<"请先从文件中读取信息!"<<endl;
else
{
first_function(HuffNode,HuffCode,total,message);
writing_HCode(HuffNode,HuffCode,total);//将编码规则写进文件
}
break;
case 5://将编码后的信息写进文件
if(mark==0)cout<<"请先从文件中读取信息!"<<endl;
else
{
first_function(HuffNode,HuffCode,total,message);
writing_lock(locking);//将已编码信息写进文件
}
break;
case 6://将译码后的信息写进文件
if(mark==0)cout<<"请先从文件中读取信息!"<<endl;
else
{
first_function(HuffNode,HuffCode,total,message);
writing_translate(locking,HuffCode,HuffNode,total);//将已编码信息翻译过来并写进文件
}
break;
}
}

/**
打印haffman树
**/
display(total,HuffNode);
system("PAUSE");
return 0;
}

void display(Total *total,HNodetype HuffNode[])
{
int i,j;
for(i=0;i<2*total->num-1;i++)
{
printf("data weight lchild rchild parent \n");
printf(" %c %d %d %d %d\n",HuffNode[i].data,HuffNode[i].weight,HuffNode[i].lchild,HuffNode[i].rchild,HuffNode[i].parent);
}

}

void reading_file(Message *message)
/**
绝对路径下读取a_test.txt file
message 中的num记录suoyou字符总数 ,放在nes【】中
equal to the buffer
**/
{
int i=0;
char ch;
ifstream infile("a_test.txt",ios::in | ios::out);
if(!infile)//打开失败则结束
{
cout<<"打开a_test.txt文件失败"<<endl;
exit(1);
}
else
cout<<"读取文件成功"<<endl;
while(infile.get(ch) && ch!='#')//读取字符直到遇到#
{
message->mes[i]=ch;
i++;
}
message->num=i;//记录总字符数
infile.close();//关闭文件
}

int writing_file(Message *message)
/**
把从数组message 的信息write to disk,a_test1.txt to save
**/
{ /*
int i;
ifstream outfile("a_test1.txt",ios::in ); //打开文件
if( !outfile )//打开失败则结束
{
cout<<"打开a_test1.txt文件失败"<<endl;
return -1;
}
for(i=0;i<message->num;i++)//写文件
outfile.put(message->mes[i]);
cout<<"信息写进文件成功"<<endl;
outfile.close();//关闭文件
return 0;*/
int i;
FILE *fp1=NULL;

if((fp1 = fopen("a_test1.txt","at"))==NULL)
{
printf("can't open the file\n");
exit(0);
}
for(i=0;i<message->num;i++)
fprintf(fp1,"%d ",message->mes[i]);
printf("文件写入成功!\n");
i=fclose(fp1);
if(i==0)
printf("文件关闭成功!\n");

else
printf("文件关闭失败!\n");
}

void total_message(Message *message,Total *total)
/**
统计message中不同字符 的个数,和相同字符重复的次数,重复字符用mark标记,
total.tot[] 放不同字符,TotalNode 类型(char,num)
total.num 统计不同字符个数
使total这块内存空间有数据,
**/
{
int i,j,mark;
for(i=0;i<message->num;i++)//遍历message中的所有字符信息
{
if(message->mes[i]!=' ')//字符不为空格时
{
mark=0;
for(j=0;j<total->num;j++)//在total中搜索当前字符
if(total->tot[j].data==message->mes[i])//搜索到,则此字符次数加1,mark标志为1
{
total->tot[j].num++;
mark=1;
break;
}
if(mark==0)//未搜索到,新建字符种类,保存进total中,字符类加1
{
total->tot[total->num].data=message->mes[i];
total->tot[total->num].num=1;
total->num++;
}
}
}
}

void HaffmanTree(Total *total,HNodetype HuffNode[])
/**create the haffman tree
不同字符个数为叶子节点个数对应书上的n,
相同字符的个数为其权值weight;
get HuffNode to store the tree
**/
{
int i,j,min1,min2,x1,x2;
for(i=0;i<2*(total->num)-1;i++)//初始化哈夫曼树并存入叶子结点权值和信息
{
if(i<=total->num-1)
HuffNode[i].data=total->tot[i].data;
HuffNode[i].weight=total->tot[i].num;
HuffNode[i].parent=-1;
HuffNode[i].lchild=-1;
HuffNode[i].rchild=-1;
}
for(i=0;i<total->num-1;i++)
{
min1=min2=MAXVALUE;
x1=x2=0;
for(j=0;j<total->num+i;j++)//选取最小x1和次小x2的两权值
{
if(HuffNode[j].parent==-1&&HuffNode[j].weight<min1)
{
min2=min1;
x2=x1;
min1=HuffNode[j].weight;
x1=j;
}
else
if(HuffNode[j].parent==-1&&HuffNode[j].weight<min2)
{
min2=HuffNode[j].weight;
x2=j;
}
}
HuffNode[x1].parent=total->num+i;//修改亲人结点位置
HuffNode[x2].parent=total->num+i;
HuffNode[total->num+i].weight=HuffNode[x1].weight+HuffNode[x2].weight;
HuffNode[total->num+i].lchild=x1;//左孩子比右孩子权值小
HuffNode[total->num+i].rchild=x2;
}
}

void HaffmanCode(HNodetype HuffNode[],HCodetype HuffCode[],Total *total)
/***
haffman to code (0,10,110,)
得到每个不同字符(叶子)的编码,
存贮在数组HuffCode【】中,bit[] store the char,start store the loction
**/
{

int i,j,c,p;
HCodetype cd;
for(i=0;i<total->num;i++)//建立叶子结点个数的编码
{
cd.start=total->num-1;//起始位初始化
p=HuffNode[i].parent;
c=i;
while(p!=-1)//从叶结点向上爬直到到达根结点
{
if(HuffNode[p].lchild==c)//左分支则为0
cd.bit[cd.start]=0;
else
cd.bit[cd.start]=1;//右分支则为1
cd.start--;//起始位向前移动
c=p;
p=HuffNode[p].parent;
}
for(j=cd.start+1;j<total->num;j++)//保存求出的每个叶结点编码和起始位
HuffCode[i].bit[j]=cd.bit[j];
HuffCode[i].start=cd.start;

}
}

void writing_HCode(HNodetype HuffNode[],HCodetype HuffCode[],Total *total)
/**
HuffNode[]to input the leaf
HuffCode[]to input the code
all is to the a_test2.txt ,save the code
**/
{
/*打开HCode文件,失败则结束。将信息写进文件*/
int i,j;
FILE *fp2=NULL;

if((fp2 = fopen("a_test2.txt","at"))==NULL)
{
printf("can't open the file\n");
exit(0);
}
for(i=0;i<total->num;i++)
{fprintf(fp2,"%d ",HuffNode[i].data);
printf(" ");
for(j=HuffCode[i].start+1;j<total->num;j++)
fprintf(fp2,"%d ",HuffCode[i].bit[j]);
}
printf("编码规则写进文件成功!\n");
i=fclose(fp2);
if(i==0)
printf("文件关闭成功!\n");

else
printf("文件关闭失败!\n");
}

void lock(Message *message,HNodetype HuffNode[],HCodetype HuffCode[],Total *total,Locking *locking)
/***
对messag操作,对所有字符加密,
结果存贮在数组locked[]中,locking 记录已经加密后的密文
**/

{
int i,j,m;
for(i=0;i<message->num;i++)//把相同的不同的字符全部 遍历
{
if(message->mes[i]==' ')//碰到空格则以-1形式保存进locked数组中
{
locking->locked[locking->num]=-1;
locking->num++;
}
else
for(j=0;j<total->num;j++)//从total中找到对应的字符
{
if(HuffNode[j].data==message->mes[i])
//找到在HuffNode 中对应字符,找到下标j
// 在HuffCode

for(m=HuffCode[j].start+1;m<total->num;m++)///////// !
{
locking->locked[locking->num]=HuffCode[j].bit[m];//加密
locking->num++;
}
}
}
}

void writing_lock(Locking *locking)
/*
将密文写到a_test3.txt
*/
{
int i;
FILE *fp3=NULL;

if((fp3= fopen("a_test3.txt","at"))==NULL)
{
printf("can't open the file\n");
exit(0);
}
for(i=0;i<locking->num;i++)
{
if(locking->locked[i]==-1)
printf(" ");
else
fprintf(fp3,"%d ",locking->locked[i]);
}
printf("已编码信息写进文件成功!\n");
i=fclose(fp3);
if(i==0)
printf("文件关闭成功!\n");

else
printf("文件关闭失败!\n");

}

void writing_translate(Locking *locking,HCodetype HuffCode[],HNodetype HuffNode[],Total *total)
/**
密文翻译成明文,然后存到文件 a_test4.txt
**/
{
int i,j,mark[100],start[100],min,max;
FILE *fp4=NULL;

if((fp4 = fopen("a_test4.txt","at"))==NULL)
{
printf("can't open the file\n");
exit(0);
}

for(i=0;i<total->num;i++)//start数组初始化
{
start[i]=HuffCode[i].start+1;//。。。。
}
for(i=0;i<total->num;i++)//mark数组初始化
{
mark[i]=1;
}
min=0;

for(max=0;max<locking->num;max++)//写文件
{
if(locking->locked[max]==-1)//碰到空格信息则直接输出空格
{
printf(" ");//把空格写到文件
min++;
}
else
{
for(i=min;i<=max;i++)//查找从min开始到max的编码对应的信息
{
for(j=0;j<total->num;j++)
{
if(start[j] == total->num+1)
mark[j]=0; //对应编码比所给编码短则不在比较
if(mark[j]==1&&locking->locked[i]==HuffCode[j].bit[start[j]])
start[j]++;
else
mark[j]=0;
}
}
for(i=0;i<total->num;i++)//找到对应信息,则写进文件
{
if(mark[i]==1&&start[i]==total->num)
{
fprintf(fp4,"%d ",HuffNode[i].data);//写到文件outfile
break;
}
}
if(i!=total->num)
min=max+1;
for(i=0;i<total->num;i++)//start数组初始化
{
start[i]=HuffCode[i].start+1;
}
for(i=0;i<total->num;i++)//mark数组初始化
{
mark[i]=1;
}
}
}
printf("文件写入成功!\n");
i=fclose(fp4);
if(i==0)
printf("文件关闭成功!\n");

else
printf("文件关闭失败!\n");
}
void first_function(HNodetype HuffNode[],HCodetype HuffCode[],Total *total,Message *message)
{
total_message(message,total);//统计信息中各字符的出现次数
HaffmanTree(total,HuffNode);//构建哈夫曼树
HaffmanCode(HuffNode,HuffCode,total);//建立哈夫曼编码

}

阅读全文

与哈夫曼编译码论文相关的资料

热点内容
银河v10驱动重编译 浏览:889
电脑上文件夹右击就会崩溃 浏览:689
右美维持算法 浏览:938
php基础编程教程pdf 浏览:219
穿越之命令与征服将军 浏览:351
android广播重复 浏览:832
像阿里云一样的服务器 浏览:318
水冷空调有压缩机吗 浏览:478
访问日本服务器可以做什么 浏览:433
bytejava详解 浏览:448
androidjava7 浏览:385
服务器在山洞里为什么还有油 浏览:886
天天基金app在哪里下载 浏览:974
服务器软路由怎么做 浏览:292
冰箱压缩机出口 浏览:228
OPT最佳页面置换算法 浏览:645
网盘忘记解压码怎么办 浏览:853
文件加密看不到里面的内容 浏览:654
程序员脑子里都想什么 浏览:434
oppp手机信任app在哪里设置 浏览:189