哈夫曼树的建立与编码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N 30
#define M 2 * N - 1


typedef struct
{
	int weight;     //权值
	int Parent, Lchild, Rchild;     //双亲,左孩子,右孩子
}HTNode, HuffmanTree[M + 1];    //哈夫曼树,0号不使用


typedef struct
{
	char ch;     //字符
	int WEI;     //权值
}weighting;


typedef struct    //堆串
{
	char* s;
	int len;
}HString;


typedef char* HuffmanCode[N];


void read(FILE* fp,char str[]);         //读入文件
weighting* getweight(char str[], weighting w[]);     //计算权值
void Printvalue(weighting w[]);      //打印权值列表
void CrtHuffmanTree(HuffmanTree ht, weighting w[], int n);      //建立哈夫曼树
void select(HuffmanTree ht, int k, int* s1, int* s2);     //选择ht前i-1项中双亲为零且权值最小的两节点s1,s
void PrintTree(HuffmanTree ht, int n);     //打印哈夫曼树
void CrtHuffmanCode(HuffmanTree ht, HuffmanCode hc, int n);    //哈夫曼编码
void PrintCode(HuffmanCode hc, int n);     //打印哈夫曼编码
void Decoding(char str[], weighting w[], HuffmanCode hc);     //译码并打印 


int main()
{
	HuffmanTree H;
	HuffmanCode T;
	weighting WEI[10000];
	HString* STR;
	FILE* fp = NULL;
	char str[10000];
	weighting* W;
	read(fp,str);
	W = getweight(str, WEI);     //计算权值
	int len = W[0].WEI;
	CrtHuffmanTree(H, W, len);       //建立哈夫曼树
	CrtHuffmanCode(H, T, len);       //哈夫曼编码
	PrintTree(H, 2 * len - 1);       //打印哈夫曼树
	PrintCode(T, len);       //打印哈夫曼编码
	Printvalue(W);      //打印每个字符和其所对应的权值
	Decoding(str, W, T);     //译码并打印
}


//读入文件
void read(FILE* fp,char str[])
{
	char filename[40];
	printf("请输入文件名:\n");
	gets_s(filename);
	fp = fopen(filename, "r");
	if (fp == NULL)
	{
		printf("\nERROR!\n");
		exit(0);
	}
	fscanf(fp, "%s", str);
	puts(str);
	fclose(fp);
}


//构造哈夫曼树
void CrtHuffmanTree(HuffmanTree ht, weighting w[], int n)
{
	int m;
	m = 2 * n - 1;
	int i;
	//初始化哈夫曼树
	for (i = 1; i <= n; i++)
	{
		ht[i].weight = w[i].WEI;
		ht[i].Rchild = 0;
		ht[i].Lchild = 0;
		ht[i].Parent = 0;
	}
	for (i = n + 1; i <= m; i++)
	{
		ht[i].weight = 0;
		ht[i].Rchild = 0;
		ht[i].Lchild = 0;
		ht[i].Parent = 0;
	}
	//给后面的结点赋值
	for (i = n + 1; i <= m; i++)
	{
		//选择树中双亲为0最小的两个值
		int s1, s2;
		select(ht, i - 1, &s1, &s2);
		ht[i].weight = ht[s1].weight + ht[s2].weight;
		ht[i].Lchild = s1;
		ht[i].Rchild = s2;
		ht[s1].Parent = i;
		ht[s2].Parent = i;
	}
}


//选择ht前i-1项中双亲为零且权值最小的两节点s1,s2
void select(HuffmanTree ht, int k, int* s1, int* s2)
{
	int i;
	int j = 0;
	int min1 = 10000;
	int min2 = 10000;
	for (i = 1; i <= k; i++)
	{
		if (ht[i].weight <= min1 && ht[i].Parent == 0)
		{
			*s1 = i;
			j = i;
			min1 = ht[i].weight;
		}
	}
	for (i = 1; i <= k; i++)
	{
		if (i == j) continue;
		else
		{
			if (ht[i].weight <= min2 && ht[i].Parent == 0)
			{
				*s2 = i;
				min2 = ht[i].weight;
			}
		}

	}
}


//哈夫曼编码
void CrtHuffmanCode(HuffmanTree ht, HuffmanCode hc, int n)
{
	char* cd;
	int i;
	int c;
	int p;
	int start;
	cd = (char*)malloc(n * sizeof(char));      //临时编码数组
	cd[n - 1] = '\0';      //从叶子节点开始遍历到根,所以首先放置\0
	for (i = 1; i <= n; i++)      //求每个叶子结点的编码,共有n个叶子结点
	{
		start = n - 1;      //从后开始编写编码
		c = i;      //c为当前节点
		p = ht[i].Parent;     //p为其双亲
		while (p != 0)       //当其不为根节点时
		{
			start--;
			if (ht[p].Rchild == c)
			{
				cd[start] = '1';
			}
			else
			{
				cd[start] = '0';
			}
			c = p;
			p = ht[p].Parent;
		}
		hc[i] = (char*)malloc((n - start) * sizeof(char));
		strcpy(hc[i], &cd[start]);
	}
	free(cd);
}


//打印哈夫曼树
void PrintTree(HuffmanTree ht, int n)
{
	int i;
	printf("Printhuffmantree:\n");
	for (i = 1; i <= n; i++)
	{
		printf("%d  %d  %d  %d\n", ht[i].weight, ht[i].Parent, ht[i].Lchild, ht[i].Rchild);
	}
}


//打印哈夫曼编码
void PrintCode(HuffmanCode hc, int n)
{
	int i;
	printf("Printcode:\n");
	for (i = 1; i <= n; i++)
	{
		puts(hc[i]);
	}

}


//计算权值
weighting* getweight(char str[], weighting* w)
{
	int i = 0;
	int j = 0;
	int k;
	int m;
	int len = strlen(str);      //字符串长度
	for (i = 0, k = 1; i < len; i++, k++)     //遍历字符串,将每一个字符记录下来,并赋初值为1
	{
		w[k].ch = str[i];
		w[k].WEI = 1;
	}
	for (i = 0, k = 1; i < len; i++, k++)
	{
		for (j = i + 1; j <= len; j++)
		{
			if (str[i] == str[j])
			{
				w[k].WEI++;
			}
		}
	}
	for (i = 1; i <= len; i++)     //遍历数组
	{
		for (j = i + 1; j <= len; j++)
		{
			if (w[i].ch == w[j].ch)
			{
				w[j].WEI = 0;
			}
		}
	}
	k = 1;
	weighting wnew[10000];
	for (i = 1; i <= len; i++)
	{
		if (w[i].WEI == 0)  continue;
		else
		{
			wnew[k] = w[i];
			k++;
		}
	}
	wnew[0].WEI = k - 1;
	w = wnew;
	return &w[0];
}


//打印权值列表
void Printvalue(weighting w[])
{
	int i;
	int len = w[0].WEI;
	printf("Printvalue:\n");
	for (i = 1; i <= len; i++)
	{
		printf("%c   %d\n", w[i].ch, w[i].WEI);
	}
}


//译码并打印
void Decoding(char str[], weighting w[], HuffmanCode hc)   //字符串、权值列表、哈夫曼编码
{
	HString HS[1000];    //堆串
	int i;
	FILE* fp;
	char filename[40];
	int len = strlen(str);
	int length = w[0].WEI;
	int j;
	for (i = 0; i < len; i++)     //遍历字符串
	{
		for (j = 1; j <= length; j++)
		{
			if (str[i] == w[j].ch)
			{
				HS[i].s = hc[j];
				HS->len++;
			}
		}
	}
	for (i = 0; i < len; i++)
	{
		printf("%s", HS[i].s);
	}
	printf("\n");
	printf("Please enter the filename:\n");
	gets_s(filename);
	errno_t err;
	fp = fopen(filename, "a+");
	if (fp == NULL)
	{
		printf("\nERROR!\n");
		exit(0);
	}
	fprintf(fp, "\nresult:");
	for (i = 0; i < len; i++)
	{
		fputs(HS[i].s, fp);
	}
	fclose(fp);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值