C代码小包

哈夫曼编码/译码器整套代码(历史博客 有详细解读):


 

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define Max 100                     //最大叶子结点个数

//定义哈夫曼树的结点
typedef struct {
	char data;     //数据域
	float weight;    //权值域
	int parent;    //双亲域
	int LChild;    //左孩子域
	int RChild;    //右孩子域
}Huffnode;
Huffnode* ht;

//定义编码的结点
typedef struct {
	char cd[Max];                //cd[]存放哈夫曼编码
	int start;
}Huffcode;
Huffcode* hc;

//菜单
void Menu()
{
	printf("*****************************************\n");
	printf("*                                       *\n");
	printf("*          哈夫曼编/译码系统            *\n");
	printf("*                                       *\n");
	printf("*****************************************\n");
	printf("*            1.调用已初始化的           *\n");
	printf("*            2.手动初始化               *\n");
	printf("*            E(e).编码                  *\n");
	printf("*            D(d).译码                  *\n");
	printf("*            P(p).打印代码文件          *\n");
	printf("*            T(t).打印哈夫曼树          *\n");
	printf("*            Q(q).退出                  *\n");
	printf("*****************************************\n");
	printf("请键入操作:");
}

//输入结点信息
void Input() {
	void Hfmtree(Huffnode * ht);
	void Huffcoding(Huffnode * ht);
	FILE* fp;
	int i, n;

	printf("enter elem number:");
	scanf_s("%d", &n);
	ht = (Huffnode*)malloc((2 * n) * sizeof(Huffnode));
	if (ht == NULL) {
		printf("wrong!");
		exit(0);
	}
	ht[0].weight = n;
	for (i = 1; i <= n; i++) {
		char a = getchar();
		printf(" %d elem data and weight(中间用空格隔开):", i);
		scanf_s("%c%f", &ht[i].data, 1, &ht[i].weight);
	}
	Hfmtree(ht);
	Huffcoding(ht);
	if ((fp = fopen("D:\\hfm\\hfmtree.txt", "w")) == NULL) {
		printf("Open file hfmtree.txt error!\n");
		exit(0);
	}
	fputs("初始化如下:\n", fp);
	fprintf(fp, "%f\n", ht[0].weight);
	for (int i = 1; i <= ht[0].weight; i++)
		fprintf(fp, "%c%f\n", ht[i].data, ht[i].weight);
	fclose(fp);
	printf("\n\n\n初始化已完成,已存入hfmtree.txt文件中!\n");
}


//初始化带权结点
void Init() {
	void Hfmtree(Huffnode * ht);
	void Huffcoding(Huffnode * ht);
	FILE* fp;
	ht = (Huffnode*)malloc((2 * Max) * sizeof(Huffnode));
	if (ht == NULL) {
		printf("wrong!");
		exit(0);
	}
	ht[0].weight = 26;
	ht[1].data = 'A'; ht[1].weight = 64;
	ht[2].data = 'B'; ht[2].weight = 13;
	ht[3].data = 'C'; ht[3].weight = 22;
	ht[4].data = 'D'; ht[4].weight = 32;
	ht[5].data = 'E'; ht[5].weight = 103;
	ht[6].data = 'F'; ht[6].weight = 21;
	ht[7].data = 'G'; ht[7].weight = 15;
	ht[8].data = 'H'; ht[8].weight = 47;
	ht[9].data = 'I'; ht[9].weight = 57;
	ht[10].data = 'J'; ht[10].weight = 1;
	ht[11].data = 'K'; ht[11].weight = 5;
	ht[12].data = 'L'; ht[12].weight = 32;
	ht[13].data = 'M'; ht[13].weight = 20;
	ht[14].data = 'N'; ht[14].weight = 57;
	ht[15].data = 'O'; ht[15].weight = 63;
	ht[16].data = 'P'; ht[16].weight = 15;
	ht[17].data = 'Q'; ht[17].weight = 1;
	ht[18].data = 'R'; ht[18].weight = 48;
	ht[19].data = 'S'; ht[19].weight = 51;
	ht[20].data = 'T'; ht[20].weight = 80;
	ht[21].data = 'U'; ht[21].weight = 23;
	ht[22].data = 'V'; ht[22].weight = 8;
	ht[23].data = 'W'; ht[23].weight = 18;
	ht[24].data = 'X'; ht[24].weight = 1;
	ht[25].data = 'Y'; ht[25].weight = 16;
	ht[26].data = 'Z'; ht[26].weight = 1;
	Hfmtree(ht);
	Huffcoding(ht);
	if ((fp = fopen("D:\\hfm\\hfmtree.txt", "w")) == NULL) {
		printf("Open file hfmtree.txt error!\n");
		exit(0);
	}
	fputs("初始化如下:\n", fp);
	fprintf(fp, "%f\n", ht[0].weight);
	for (int i = 1; i <= ht[0].weight; i++)
		fprintf(fp, "%c%f\n", ht[i].data, ht[i].weight);
	fclose(fp);
	printf("\n\n\n初始化已完成,已存入hfmtree.txt文件中!\n");
}


//创建哈夫曼树
void Hfmtree(Huffnode* ht) {
	float n, m1, m2;
	int i, k, x1, x2;                    /*m1为最小权值,x1为其对应的下标;
										   m2为次小权值,x2为其对应的下标*/
	n = ht[0].weight;        /*ht[0].weight存放的是字符数*/
	for (i = 1; i <= 2 * n - 1; i++)
		ht[i].parent = ht[i].LChild = ht[i].RChild = 0;       /*对所有的ht[]的parent、LChile、RChild域进行初始化*/
	for (i = n + 1; i <= 2 * n - 1; i++) {          /*创建非叶结点,构建哈夫曼树*/
		m1 = m2 = 10000;     /*初始值赋的大一些*/
		x1 = x2 = 0;
		for (k = 1; k <= i - 1; k++)          /*k为可进行比较的结点的下标;
									  在ht[1]~ht[i-1]的范围内选择两个parent为0且weight最小的结点,其序号分别赋给x1、x2*/
			if (ht[k].parent == 0)
				if (ht[k].weight < m1) {
					m2 = m1;
					x2 = x1;
					m1 = ht[k].weight;
					x1 = k;
				}
				else if (m1 < ht[k].weight < m2) {
					m2 = ht[k].weight;
					x2 = k;
				}
		ht[i].weight = ht[x1].weight + ht[x2].weight;
		ht[x1].parent = i; ht[x2].parent = i;
		ht[i].LChild = x1; ht[i].RChild = x2;
	}
}

//创建哈夫曼编码
void Huffcoding(Huffnode* ht) {
	char d[Max];
	float n;
	int i, start, c, p;
	n = ht[0].weight;
	hc = (Huffcode*)malloc(Max * sizeof(Huffcode));          //分配当前编码的工作空间
	if (hc == NULL) {
		printf("wrong!\n");
		exit(0);
	}
	for (i = 1; i <= n; i++) {                                             //h[i]
		start = n;       //初始化编码起始指针
		c = i;               //从叶子结点开始向上倒推
		p = ht[i].parent;
		while (p != 0) {
			--start;                       //从右向左逐位存放编码,首先放结束符
			if (ht[p].LChild == c)
				d[start] = '0';
			else
				d[start] = '1';
			c = p;
			p = ht[p].parent;
		}
		hc[i].start = start;
		for (int k = start; k < n; k++) {
			hc[i].cd[k] = d[k];
		}
	}
}


//编码函数
void Encoding() {
	FILE* fp, * fp1;
	int i, m = 0;
	char a;
	char in[Max];
	char in1[Max];
	char out[Max * Max];
	if ((fp = fopen("D:\\hfm\\ToBeTran.txt", "a+")) == NULL) {
		printf("Open file ToBeTran.txt error!\n");
		exit(0);
	}
	if ((fp1 = fopen("D:\\hfm\\CodeFile.txt", "w")) == NULL) {
		printf("Open file ToBeTran.txt error!\n");
		exit(0);
	}

	//判断ToBeTran.txt是否为空
	if (fgetc(fp) == EOF) {
		printf("ToBeTran.txt文件为空\n请在相应位置打开文件输入\n\n");
		exit(0);
	}
	else {
		printf("成功读取ToBeTran.txt文件\n");
	}

	fseek(fp, 0L, SEEK_SET);         //定位到文件开始处
	fgets(in, Max, fp);
	int n = (int)strlen(in);
	for (i = 0; i < n; i++)
		for (int j = 1; j <= ht[0].weight; j++)
			if (in[i] == ht[j].data) {
				for (int k = hc[j].start; k < ht[0].weight; k++) {
					out[m++] = hc[j].cd[k];
				}
			}
	for (i = 0; i < m; i++)
		fprintf(fp1, "%c", out[i]);
	printf("\n\n\n编码结束,结果已存入CodeFile.txt文件中!\n");
	fclose(fp);
	fclose(fp1);
}


//译码函数
void Decoding() {
	FILE* fp, * fp1;
	int i, j, n, k, x, m, w;
	char out[Max];
	char in[Max * Max];
	if ((fp = fopen("D:\\hfm\\CodeFile.txt", "r")) == NULL) {
		printf("Open file CodeFile.txt error!\n");
		exit(0);
	}
	if ((fp1 = fopen("D:\\hfm\\TextFile.txt", "w")) == NULL) {
		printf("Open file TextFile.txt error!\n");
		exit(0);
	}
	fgets(in, Max * Max, fp);
	if ((int)strlen(in)) {
		printf("成功读取CodeFile.txt文件\n");
	}
	n = (int)strlen(in);
	i = 0; m = 0;
	while (i < n) {
		for (j = 1; j <= ht[0].weight; j++) {
			x = hc[j].start;
			for (k = x, w = i; k < ht[0].weight; k++, w++)
				if (in[w] != hc[j].cd[k])
					break;
			if (k >= ht[0].weight) {
				out[m++] = ht[j].data;
				break;
			}
		}
		i = w;
	}
	for (i = 0; i < m; i++)
		fprintf(fp1, "%c", out[i]);
	printf("\n\n\n译码结束,结果已存入TextFile.txt文件中!\n");
	fclose(fp);
	fclose(fp1);
}


//打印编码
void Print()
{
	FILE* fp, * fp1;
	int i = 0;
	int j = 0;
	char in[Max * Max];
	printf("代码文件为:\n");
	if ((fp = fopen("D:\\hfm\\CodeFile.txt", "r")) == NULL) {
		printf("Open file CodeFile.txt error!\n");
		exit(0);
	}
	if ((fp1 = fopen("D:\\hfm\\CodePrin.txt", "w")) == NULL) {
		printf("Open file CodePrin.txt error!\n");
		exit(0);
	}
	fgets(in, Max * Max, fp);
	int n = (int)strlen(in);
	for (; i < n; i++) {
		printf("%c", in[i]);
		fprintf(fp1, "%c", in[i]);
		j++;
	}
	printf("\n\n\n\n代码文件已存入CodePrin.txt文件中\n");
	fclose(fp);
	fclose(fp1);
}



//打印树
int DEPTH = 0;
void PreOrderTraverse(FILE* fp, int k) {
	int i;

	if (ht[k].RChild != 0) {
		DEPTH++;
		PreOrderTraverse(fp, ht[k].RChild);
		DEPTH--;
	}
	for (i = 0; i <= DEPTH; i++) {
		printf("    ");
		fprintf(fp, "        ");
	}
	printf("%f\n", ht[k].weight);
	fprintf(fp, "%f\n", ht[k].weight);

	if (ht[k].LChild != 0) {
		DEPTH++;
		PreOrderTraverse(fp, ht[k].LChild);
		DEPTH--;
	}

	if (ht[k].LChild == 0 && ht[k].RChild == 0)
		return;
	return;

}
void TreePrinting() {
	FILE* fp;
	if ((fp = fopen("D:\\hfm\\TreePrint.txt", "w")) == NULL) {
		printf("Open file TreePrint.txt error!\n");
		exit(0);
	}
	printf("哈夫曼树凹入表:\n");
	PreOrderTraverse(fp, ht[0].weight * 2 - 1);
	printf("\n\n\n\n凹入表已写入TreePrint.txt文件中\n");
	fclose(fp);
}

//释放空间
void Free() {
	free(ht);
	free(hc);
}


//主函数
int main() {
	char select;
	while (1) {
		Menu();
		scanf_s("%c", &select, 1);
		switch (select) {

		case '1':Init(); break;

		case '2':Input(); break;
		case 'e':
		case 'E':Encoding(); break;
		case 'd':
		case 'D':Decoding(); break;
		case 'p':
		case 'P':Print(); break;
		case 't':
		case 'T':TreePrinting(); break;
		case 'q':
		case 'Q':Free(); exit(1);
		default:printf("Input error!\n");
		}
		int x = getchar();
	}
}

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@ooneo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值