哈夫曼编码C语言实现

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了哈夫曼编码C语言实现相关的知识,希望对你有一定的参考价值。

我写了一个注释较为完整且压缩、解压缩比较全面的:

#include <stdio.h>
#include <conio.h>

#define MAX_FILE 5000/* 假设的文件最大长度 */
#define MAXLIST 256/* 最大MAP值 */
#define MAX_HOFFMAN_LENGTH 50/* 哈夫曼编码长度 */
char dictionary[MAXLIST][2]=0;/* Hash映射,[][0]为权值,[][1]为字符 */
char fileContent[MAX_FILE];/* 处理的字符串大小 */
int Hoffman[MAXLIST][MAX_HOFFMAN_LENGTH]=2;/* 哈夫曼编码序列 */
char HoffmanList[MAXLIST]=0;/* 哈夫曼编码对应的字符有序序列 */
char HoffFileCode[MAX_FILE]=0;/* 哈夫曼编码字符串序列 */
char HoffFile[MAX_FILE]=0;
/* 编码到假设的文件的哈夫曼压缩格式: 依次存储 原字符串长度(1字节存储:可扩展到2字节)、哈夫曼编码数(1字节)、每个哈夫曼编码的长度序列、每个哈夫曼编码对应的字符序列、编码过的哈夫曼字符串 */

char GetFile[MAX_FILE]=0;/* 解码序列 */

void ShellSort(char pData[MAXLIST][2],int Count)/* Shell排序,用于准备有序化要构造的编码权值构造哈夫曼树做准备 */

int step[4]=9,5,3,1;/* 增量序列 */

int iTemp,cTemp;
int k,s,w,i,j;
for(i=0;i<4;i++)

k=step[i];
s=-k;
for(j=k;j<Count;j++)
iTemp=pData[j][0];
cTemp=pData[j][1];
w=j-k;
if(s==0)

s=-k;
s++;
pData[s][0]=iTemp;
pData[s][1]=cTemp;

while((iTemp<pData[w][0])&&(w>=0)&&(w<=Count))

pData[w+k][0]=pData[w][0];/* 权值交换 */
pData[w+k][1]=pData[w][1];/* 字符交换 */
w=w-k;

pData[w+k][0]=iTemp;
pData[w+k][1]=cTemp;




struct TNode/* 哈夫曼树结点 */

struct TNode* pNode;
struct TNode* lNode;
struct TNode* rNode;
char dictionary;
char weight;

;

void TNode_init(struct TNode*tn,char dic,char wei)

tn->pNode=0;
tn->lNode=0;
tn->rNode=0;
tn->dictionary=dic;
tn->weight=wei;

struct LNode/* 链表结点,用于存储哈夫曼树结点,进而构造哈夫曼树(保证每一步链表结点包含的哈夫曼结点都是有序的) */

struct LNode* prev;
struct LNode* next;
struct TNode* tnode;

;

void LNode_init(struct LNode* ln)

ln->prev=ln->next=0;
ln->tnode=0;


int len=0;/* 哈夫曼编码数 */
int deep=-1;/* 深度 */
void Preorder(struct TNode * p);/* 前序遍历 */
void byLeft(struct TNode*p)/* 经由左结点 */

deep++;
Hoffman[len][deep]=0;
Preorder(p);

Hoffman[len][deep]=2;
deep--;

void byRight(struct TNode*p)/* 经由右结点 */


deep++;
Hoffman[len][deep]=1;
Preorder(p);

Hoffman[len][deep]=2;
deep--;

void Preorder(struct TNode * p)


int i;
if(p->lNode!=0)/* 当左子结点非空则遍历 */


byLeft(p->lNode);

if(p->rNode!=0)/* 当右子结点非空则遍历 */

byRight(p->rNode);


if((p->lNode==0)&&(p->rNode==0))/* 当左右结点都为空,则增加哈夫曼编码数到另一个记录 */


Hoffman[len][deep+1]=2;
i=0;
for(;Hoffman[len][i]!=2;i++)

Hoffman[len+1][i]=Hoffman[len][i];

Hoffman[len+1][i]=2;

HoffmanList[len]=p->dictionary;

len++;




char generateOne(int k)/* 产生k个连续1的二进制串,比如111,1111,111111,用于编码进假设的文件 */

char c=0;
for(;k!=0;k--)

c|=(1<<(k-1));


return c;


int compareBits(char b1,char b2,char c,int l,int d)/* 判断由 [b1,b2] 组成的16位二进制数以d为起点,是否是长度为l的c二进制串(哈夫曼编码)的前缀 */

unsigned char t=(((((0x00ff&b1)<<8)|(0x00ff&b2))>>(8-d))&0x00ff);
return (((t)&((generateOne(l)<<(8-l))&0xff))==((c<<(8-l))&0xff));


int main()

struct LNode* t,*p;
struct LNode* head;
struct TNode *tempTNode,*k1;
int i=0,j,k;
unsigned short fileLen=0;
int len=0,l,b1,b2,d;
char c;
int code[500],h=0;
int codeLen=0,total=0;
/* 或许假定的文件字符串向量中的字符串 */

printf("please Enter string to be pressed:");
scanf("%s",&fileContent);

/* Hash进dictionary */

for(;fileContent[i]!='\0';i++,fileLen++)


++dictionary[fileContent[i]][0];
dictionary[fileContent[i]][1]=fileContent[i];


/* 把Hash了的dictionary向前靠拢 */



for(i=0;i!=MAXLIST;i++)


if(dictionary[i][0]!=0)

dictionary[len][0]=dictionary[i][0];
dictionary[len][1]=dictionary[i][1];
len++;



printf("the number of Huffman's codes:%d\n",len);
/* 对dictionary按权值进行排序 */

ShellSort(dictionary,len);

/* 构造链表,链表中放有序dictionary权值的树结点 */
head=(struct LNode*)malloc(sizeof(struct LNode)),p=head;
LNode_init(head);
head->next=(struct LNode*)malloc(sizeof(struct LNode));
LNode_init(head->next);

tempTNode=(struct TNode*)malloc(sizeof(struct LNode));
TNode_init(tempTNode,dictionary[0][1],dictionary[0][0]);
head->tnode=tempTNode;


for(i=0;i!=len-1;i++)

p->next->prev=p->next;
p=p->next;

p->next=(struct LNode*)malloc(sizeof(struct LNode));
LNode_init(p->next);

tempTNode=(struct TNode*)malloc(sizeof(struct TNode)) ;
TNode_init(tempTNode,dictionary[i+1][1],dictionary[i+1][0]);
p->tnode=tempTNode;


free(p->next);
p->next=0;

/* 每次最小权值的前面两个链表结点中的树结点组成一个子树,子树有合权值,子数的根按权值排序进链表*/

for(p=head;p->next!=0;)


p->tnode->pNode=(struct TNode*)malloc(sizeof(struct TNode)) ;
TNode_init(p->tnode->pNode,'\0',(p->tnode->weight)+(p->next->tnode->weight));

p->next->tnode->pNode=p->tnode->pNode;
p->tnode->pNode->lNode=p->tnode;
p->tnode->pNode->rNode=p->next->tnode;
head=p->next;
free(p);
p=head;
p->tnode=p->tnode->pNode;
for(t=head;t->next!=0;t=t->next)

if(t->tnode->weight>t->next->tnode->weight)

k1=t->tnode;
t->tnode=t->next->tnode;
t->next->tnode=k1;





/* 前序遍历构造哈夫曼编码 */
Preorder(p->tnode);


for(i=0;i!=len;i++)
dictionary[HoffmanList[i]][0]=i;

/* 存储字符串的哈夫曼压缩编码串,并且打包文件格式 */


for(i=0;i!=fileLen;i++)

int j=dictionary[fileContent[i]][0];
for(k=0;Hoffman[j][k]!=2;k++)


HoffFileCode[codeLen]|=(Hoffman[j][k]<<(7-total%8));
code[h++]=Hoffman[j][k];

if(((total+1)%8)==0)

HoffFile[1+len*3+1+codeLen]=HoffFileCode[codeLen];
codeLen++;

total++;




HoffFile[1+len*3+1+codeLen]=HoffFileCode[codeLen];
HoffFile[0]=(fileLen);

/* 解压缩假定的文件HoffFile成为原字符串序列 */
printf("Huffman's code list:\n");
HoffFile[1]=len;


for(i=0,j=0;i!=len;i++,j=0)


for(;Hoffman[i][j]!=2;j++);

HoffFile[i+2]=j;
HoffFile[i+2+2*len]=HoffmanList[i];

for( k=0;k!=j;k++)


printf("%d",Hoffman[i][k]);
HoffFile[i+2+len]|=(Hoffman[i][k]<<(j-1-k));


printf(":%d\n",HoffmanList[i]);





for(i=0,j=0;i!=(HoffFile[0]&0xff);i++)

for(k=0;k!=HoffFile[1];k++)


l=HoffFile[2+k],d=j%8,b1=HoffFile[j/8+2+HoffFile[1]*3],b2=HoffFile[j/8+1+2+HoffFile[1]*3];

c=HoffFile[HoffFile[1]+2+k];

if(compareBits(b1,b2,c,l,d))


j+=HoffFile[2+k];

GetFile[i]=HoffFile[2+HoffFile[1]*2+k];

break;







printf("Huffman code List Pressed :\n");
for(i=0;i!=h;i++)

printf("%c",code[i]);
if((i+1)%8==0)
printf(" ");


printf("\n");


printf("Huffman code packaged:\n");
for(i=0;i!=HoffFile[0]+HoffFile[1]*3;i++)

printf("%c",HoffFile[i]);

printf("\n");


printf("The initial len :%d\n",fileLen);
printf("The string len pressed:%d\n",(h)/8+1);
printf("The rate%.2f\%",((h/8.0+1)/fileLen)*100);



printf("The number of bytes:%d\n",(HoffFile[0]&0xff));
printf("The string decoded:");
for(i=0;i!=(HoffFile[0]&0xff);i++)

printf("%c",GetFile[i]);


printf("\n");


getch();
return 1;
参考技术A /*文件名:exp7-6.cpp*/
#include <stdio.h>
#include <string.h>
#define N 50 /*叶子结点数*/
#define M 2*N-1 /*树中结点总数*/
typedef struct

char data[5]; /*结点值*/
int weight; /*权重*/
int parent; /*双亲结点*/
int lchild; /*左孩子结点*/
int rchild; /*右孩子结点*/
HTNode;
typedef struct

char cd[N]; /*存放哈夫曼码*/
int start;
HCode;
void CreateHT(HTNode ht[],int n)

int i,k,lnode,rnode;
int min1,min2;
for (i=0;i<2*n-1;i++) /*所有结点的相关域置初值-1*/
ht[i].parent=ht[i].lchild=ht[i].rchild=-1;
for (i=n;i<2*n-1;i++) /*构造哈夫曼树*/

min1=min2=32767; /*lnode和rnode为最小权重的两个结点位置*/
lnode=rnode=-1;
for (k=0;k<=i-1;k++)
if (ht[k].parent==-1) /*只在尚未构造二叉树的结点中查找*/

if (ht[k].weight<min1)

min2=min1;rnode=lnode;
min1=ht[k].weight;lnode=k;

else if (ht[k].weight<min2)

min2=ht[k].weight;rnode=k;


ht[lnode].parent=i;ht[rnode].parent=i;
ht[i].weight=ht[lnode].weight+ht[rnode].weight;
ht[i].lchild=lnode;ht[i].rchild=rnode;


void CreateHCode(HTNode ht[],HCode hcd[],int n)

int i,f,c;
HCode hc;
for (i=0;i<n;i++) /*根据哈夫曼树求哈夫曼编码*/

hc.start=n;c=i;
f=ht[i].parent;
while (f!=-1) /*循序直到树根结点*/

if (ht[f].lchild==c) /*处理左孩子结点*/
hc.cd[hc.start--]='0';
else /*处理右孩子结点*/
hc.cd[hc.start--]='1';
c=f;f=ht[f].parent;

hc.start++; /*start指向哈夫曼编码最开始字符*/
hcd[i]=hc;


void DispHCode(HTNode ht[],HCode hcd[],int n)

int i,k;
int sum=0,m=0,j;
printf(" 输出哈夫曼编码:\n"); /*输出哈夫曼编码*/
for (i=0;i<n;i++)

j=0;
printf(" %s:\t",ht[i].data);
for (k=hcd[i].start;k<=n;k++)

printf("%c",hcd[i].cd[k]);
j++;

m+=ht[i].weight;
sum+=ht[i].weight*j;
printf("\n");

printf("\n 平均长度=%g\n",1.0*sum/m);

void main()

int n=15,i;
char *str[]=;
int fnum[]=;
HTNode ht[M];
HCode hcd[N];
for (i=0;i<n;i++)

strcpy(ht[i].data,str[i]);
ht[i].weight=fnum[i];

printf("\n");
CreateHT(ht,n);
CreateHCode(ht,hcd,n);
DispHCode(ht,hcd,n);
printf("\n");


以前写的,你照着改下就行的.
参考技术B /*文件名:exp7-6.cpp*/
#include <stdio.h>
#include <string.h>
#define N 50 /*叶子结点数*/
#define M 2*N-1 /*树中结点总数*/
typedef struct

char data[5]; /*结点值*/
int weight; /*权重*/
int parent; /*双亲结点*/
int lchild; /*左孩子结点*/
int rchild; /*右孩子结点*/
HTNode;
typedef struct

char cd[N]; /*存放哈夫曼码*/
int start;
HCode;
void CreateHT(HTNode ht[],int n)

int i,k,lnode,rnode;
int min1,min2;
for (i=0;i<2*n-1;i++) /*所有结点的相关域置初值-1*/
ht[i].parent=ht[i].lchild=ht[i].rchild=-1;
for (i=n;i<2*n-1;i++) /*构造哈夫曼树*/

min1=min2=32767; /*lnode和rnode为最小权重的两个结点位置*/
lnode=rnode=-1;
for (k=0;k<=i-1;k++)
if (ht[k].parent==-1) /*只在尚未构造二叉树的结点中查找*/

if (ht[k].weight<min1)

min2=min1;rnode=lnode;
min1=ht[k].weight;lnode=k;

else if (ht[k].weight<min2)

min2=ht[k].weight;rnode=k;


ht[lnode].parent=i;ht[rnode].parent=i;
ht[i].weight=ht[lnode].weight+ht[rnode].weight;
ht[i].lchild=lnode;ht[i].rchild=rnode;


void CreateHCode(HTNode ht[],HCode hcd[],int n)

int i,f,c;
HCode hc;
for (i=0;i<n;i++) /*根据哈夫曼树求哈夫曼编码*/

hc.start=n;c=i;
f=ht[i].parent;
while (f!=-1) /*循序直到树根结点*/

if (ht[f].lchild==c) /*处理左孩子结点*/
hc.cd[hc.start--]='0';
else /*处理右孩子结点*/
hc.cd[hc.start--]='1';
c=f;f=ht[f].parent;

hc.start++; /*start指向哈夫曼编码最开始字符*/
hcd[i]=hc;


void DispHCode(HTNode ht[],HCode hcd[],int n)

int i,k;
int sum=0,m=0,j;
printf(" 输出哈夫曼编码:\n"); /*输出哈夫曼编码*/
for (i=0;i<n;i++)

j=0;
printf(" %s:\t",ht[i].data);
for (k=hcd[i].start;k<=n;k++)

printf("%c",hcd[i].cd[k]);
j++;

m+=ht[i].weight;
sum+=ht[i].weight*j;
printf("\n");

printf("\n 平均长度=%g\n",1.0*sum/m);

void main()

int n=15,i;
char *str[]=;
int fnum[]=;
HTNode ht[M];
HCode hcd[N];
for (i=0;i<n;i++)

strcpy(ht[i].data,str[i]);
ht[i].weight=fnum[i];

printf("\n");
CreateHT(ht,n);
CreateHCode(ht,hcd,n);
DispHCode(ht,hcd,n);
printf("\n");


以前写的,你照着改下就行的.
我可以帮助你,你先设置我最佳答案后,我百度Hii教你。
参考技术C 我空间有篇C++的,大学时候写的,你稍微改一下就成了 参考技术D 刚刚写好,放到我百度空间上了,顺便给你粘上吧
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100
#define MAXWEIGHT 32767
typedef char elemtype; //now elemtype is char
/*树结点的数据结构*/
typedef struct

elemtype data;
int rchild;
int lchild;
int parent;
int weight;
huffnode;
/*结点哈夫曼编码的数据结构*/
typedef struct

char ch[MAXSIZE];
int start;
huffcode;
/*对所有结点初始化,得到森林*/
void initializeHuffmanTree(huffnode ht[],int n)

int i;
for(i=0;i<2*n-1;i++)
ht[i].lchild=ht[i].rchild=ht[i].parent=-1;//单一结点为一树的情况,无任何亲人
//输入结点字符、权值
for(i=0;i<n;i++)

scanf(

以上是关于哈夫曼编码C语言实现的主要内容,如果未能解决你的问题,请参考以下文章

h5房卡源码C语言实现哈夫曼树编码解码及问题总结

哈夫曼树(C语言实现)

数据结构===哈夫曼编码实现/C或者C++

基于哈夫曼树的任意文件解压缩实现

二叉树的基本操作及哈夫曼编码系统的实现

哈夫曼树定义及其构造和编码(C语言)