哈夫曼编码解码实现—数据结构
直接上小黑车 !
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define maxsize 100
#define OTF 10000000
//构造哈夫曼树--最优二叉树
typedef struct {
char data;//表示作为叶子结点的那个字符
int weight;//权值
int parent,lchild,rchild;// 父亲、左孩子、右孩子
} HuffmanNode,*HuffmanTree;
//哈夫曼编码
typedef struct {
char data;//结点表示的字符
char *code;//存储编码
} HuffmanCodeNode,*HuffmanCode;
void InitTree(HuffmanTree &T,int n);//初始化树
void sort(HuffmanTree T,int &lchild,int &rchild,int m);//查找最小的两个权值
void creatTree(HuffmanTree &T,int n);//构造哈夫曼树--最优二叉树
void InitCode(HuffmanTree T,HuffmanCode &C,int n);//初始化哈夫曼编码
void creatCode(HuffmanTree T,HuffmanCode &C,int n);//创建哈夫曼编码
void InitTree(HuffmanTree &T,int n) {
T=(HuffmanNode *)malloc(sizeof(HuffmanNode)*(2*n-1));
for(int i=0; i<2*n-1; i++) {
T[i].parent=T[i].lchild=T[i].rchild=0;
}
printf("请输入n个结点的字符和权值:按照顺序\n");
getchar();
for(int i=0; i<n; i++) {
scanf("%c %d",&T[i].data,&T[i].weight);//输入即将构造哈夫曼树的结点
getchar();//吞掉'\n'
}
}
void sort(HuffmanTree T,int &lchild,int &rchild,int m) {
int mini=OTF;
for(int i=1; i<m; i++) {
if(T[i].weight<=mini&&T[i].parent==0) {
mini=T[i].weight;
lchild=i;
}
}
mini=OTF;
for(int i=1; i<m; i++) {
if(T[i].parent==0&&T[i].weight<=mini&&i!=lchild) {
mini=T[i].weight;
rchild=i;
}
}
}
void creatTree(HuffmanTree &T,int n) {
//初始化T
InitTree(T,n);
//创建新结点
for(int i=n; i<2*n-1; i++) {
int lchild=0;
int rchild=0;
//用于返回两个最小的结点的下标,以便赋值这两个结点parent and 此结点的左右孩子
sort(T,lchild,rchild,i);//选择两个最小的结点的权值,并且是parent=0的
T[lchild].parent=i;//从表中删除lchild,rchild
T[rchild].parent=i;
T[i].lchild=lchild;//作为i的孩子
T[i].rchild=rchild;
T[i].weight=T[lchild].weight+T[rchild].weight;//权值之和
}
}
//获取哈夫曼编码
void InitCode(HuffmanTree T,HuffmanCode &C,int n) {
C=new HuffmanCodeNode[n];//创建n个数组,内部又有一个char数组
for(int i=0; i<n; i++) {
C[i].data=T[i].data;//初始化
}
}
void creatCode(HuffmanTree T,HuffmanCode &C,int n) {
InitCode(T,C,n);
for(int i=0; i<n; i++) {
char *cd;//装哈夫曼编码
cd=new char[n];//总共n个结点,n个编码,但是编码的长度最大为n-1所以最后以为存储'\0'结束标语
cd[n-1]='\0';//strcpy是将源头字符串包括’\0’复制到另一个地址空间,这样才能确保目的地字符串有字符串结束的标志’\0’,程序不会崩溃。
int end=T[i].parent;//end直到parent==0表示已经到根结点
int start=n-1;//start从后面开始因为编码从叶子到根结点,相反,所以读一个放在cd数组的后面,从而顺过来
int nowi=i;//当前结点,因为需要向上寻找
while(end!=0) {
start--;
if(T[end].lchild==nowi) cd[start]='0';
else cd[start]='1';
nowi=end;
end=T[end].parent;
}
C[i].code=new char[n-start];//strcpy是将源头字符串包括’\0’复制到另一个地址空间,这样才能确保目的地字符串有字符串结束的标志’\0’,程序不会崩溃。
strcpy(C[i].code,&cd[start]);//就是将cd字符复制到C[i].code完全是cd的字符串
delete cd;
}
}
int main() {
/*
A 40
B 30
C 15
D 5
E 4
F 3
G 3
*/
HuffmanTree T;
printf("请输入结点个数\n");
int n;
scanf("%d",&n);
creatTree(T,n);
printf("哈夫曼树\n");
for(int i=0; i<2*n-1; i++) {
printf("%c %d\n",T[i].data,T[i].weight);
}
char sentence[maxsize];
printf("请输入你要编码的字符串:只含有ABCDEFG\n");
scanf("%s",&sentence);
for(int i=0; i<strlen(sentence); i++) {
for(int j=0; j<n; j++) {
if(sentence[i]==C[j].data) {
printf("%s",C[j].code);
break;
}
}
}
printf("\n");
printf("哈夫曼编码\n");
HuffmanCode C;
creatCode(T, C,n);
for(int i=0; i<n; i++) {
printf("%c %s\n",C[i].data,C[i].code);
}
printf("哈夫曼解码:\n");
FILE *fp=fopen("E:\\科目\\数据结构与算法\\代码实现\\哈夫曼编码.txt","r");
char ch;
HuffmanNode *p;
p=&T[2*n-2];
while(EOF!=(ch=fgetc(fp))) {
if(ch=='1')
p=&T[p->rchild];
else
p=&T[p->lchild];
if(p->data!='\0') {
printf("%c",p->data);
p=&T[2*n-2];
}
}
return 0;
}
结果输出:
/*
请输入结点个数
7
请输入n个结点的字符和权值:按照顺序
A 40
B 30
C 15
D 5
E 4
F 3
G 3
哈夫曼树
A 40
B 30
C 15
D 5
E 4
F 3
G 3
6
9
15
30
60
100
哈夫曼编码
A 1
B 01
C 001
D 00011
E 00010
F 00001
G 00000
请输入你要编码的字符串:只含有ABCDEFG
ABCDAGFEFFEABBDCDD
10100100011100000000010001000001000010001010101000110010001100011
哈夫曼解码:
ABCDAGFEFFEABBDCDD
*/
多多指教!