哈夫曼编码解码C语言实现---数据结构

哈夫曼编码解码实现—数据结构

直接上小黑车 !

#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
*/

多多指教!


  • 6
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值