哈夫曼树(HuffmanTree)

1.编写程序任意输入结点个数、结点信息和结点权值,构造一棵哈夫曼树,生成哈夫曼编码序列,并验证是否正确。

采用不同的权值序列进行哈夫曼树的创建,检验其编码的正确性。

采用不同的选择方式生成相应的哈夫曼树及其编码。

#全代码在最后。

  • 第一题:

运行结果如下:

代码讲解:

1、存储结构

typedef struct{
	ElemType elem;
	int weight;
	int parent,lchild,rchild;
}HTNode,*HuffmanTree;

结合教材,也为方便,故采用顺序结构体数组;

elem 用于存放字符,weight用于存放权值;

parent、lchild、rchild 用于存放其父、左孩子、右孩子的位置

2、Huffman树的初始化前奏

typedef struct weight
{
	char elem; 
	int  weight1; 
}Weight; // 保存字符权值
	Weight *w;
	int n,i;
	printf("请输入Huffman树的结点个数:");
	scanf("%d",&n);
	w=(Weight *)malloc(n*sizeof(Weight));
	printf("\n注意,字符和权值之间需以空格作间隔\n\n");
	for(i=0;i<n;i++){
		printf("请输入第%d个结点的代码和其权值 : ",i+1);
		scanf("%ls%d",&w[i].elem,&w[i].weight1);
	}

用其他结构体来提前存储Huffman树的字符信息和权值,简单,防止混淆

3、构造Huffman树函数

// 构造huffman树
void CreateHuffmantree(HuffmanTree &HT,int n,Weight* &w){
	void OutPutHuffmanTree(HuffmanTree HT,int n);
	if(n<=1)return;
	int i,s1,s2;
	int m=2*n-1;
	HT=(HuffmanTree)malloc( (m+1) *sizeof(HTNode));// 从1开始
	for(i=1;i<=n;i++){
		HT[i].elem=w[i-1].elem;
		HT[i].weight=w[i-1].weight1;
		HT[i].parent=0;
		HT[i].lchild=0;
		HT[i].rchild=0;
	}
	for(i=n+1;i<=m;i++){
		HT[i].elem='-';
		HT[i].weight=0;
		HT[i].parent=0;
		HT[i].lchild=0;
		HT[i].rchild=0;
	}
	printf("HT树的初态:\n");
	OutPutHuffmanTree(HT,n);
	for(i=n+1;i<=m;i++){
		Select(HT,i-1,s1,s2);
		HT[s1].parent=i,HT[s2].parent=i;
		if(s1<s2){
			HT[i].lchild=s1;
			HT[i].rchild=s2;           
		}
		else{
			HT[i].lchild=s2;
			HT[i].rchild=s1;           
		}
        HT[i].weight=HT[s1].weight+HT[s2].weight;
	}
 
}

首先,开辟一段的HTNode型的空间,易知,N个结点需合并N-1次,故需2*n-1段空间,且由于0号位不用,故多开辟一段空间;

其次,开始初始化,将结构体数组 w 的值传入huffman树中,并将后面的树除字符信息外全设为0;

最后,进行合并。在合并循环中,利用Select函数选出前n个结点权值最小且未被选过(其parent=0)的两个,并将当前循环的i作为其父,选出较小的作为左孩子,较大的作为右孩子,直至循环完毕,由此生成Huffman树。

4、Select 函数:

void Select(HuffmanTree HT,int n,int &s1,int &s2){
	int min,i;
	// 首先选出第一个最小值
	for(i=1;i<=n;i++){
		if(HT[i].parent==0){
			min=i;
			break;
		}
	}
	for(i=min+1;i<=n;i++){
		if(HT[i].parent==0&&(HT[i].weight<HT[min].weight) ){
			min=i;
		}
	}
	s1=min;
	// 再选出第二个最小值
	for(i=1;i<=n;i++){
		if(HT[i].parent==0 && i!=s1){
			min=i;
			break;
		}
	}
	for(i=min+1;i<=n;i++){
		if(HT[i].parent==0 &&(HT[i].weight<HT[min].weight) && i!=s1){
			min=i;
		}
	}
	s2=min;
}

函数比较简单,首先选出一个未被选过(parent=0)的结点,然后逐一比较后面同样未被选过为结点,得到最小的结点;

然后,再选出一个未被选过的结点,同样比较,但结点位置宇上一结点位置不能相同。

5、Huffman编码函数:


void CreateHuffmanCode(HuffmanTree &HT,HuffmanCode &HC,int n){
	HC=(HuffmanCode)malloc(n*sizeof(char *) ); // 分配n个字符编码
	if(!HC)return;
	char *cd; // 作为临时存储编码的空间
	int i,c,f,start; // 临时变量
	cd = (char *)malloc(n*sizeof(char));
	cd[n-1] = '\0'; // 编码结束符,方便复制
	for(i=1;i<=n;i++){
        start=n-1;
		for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent){
			if(HT[f].lchild==c){cd[--start]='0';}
			else{cd[--start]='1';}
		}
		HC[i]=(char *)malloc( (n-start)*sizeof(char));
		strcpy(HC[i],&cd[start]);
	}
	free(cd);
}

该函数是从叶子逆向求每个字符的Huffman编码;

首先,分配n个字符编码的头指针向量,接着分配求编码的工作空间;

其次,在循环中,找起父节点,并以 HT[i].pareng!=0 为终止条件,如果,其为其父的左结点,则让cd[--start]=‘1’,否则为‘0’;其中,cd空间为倒叙输入,为方便输出,且不使用栈;

最后,为第i个字符编码开辟空间,并将已经编好的码赋值给它。

采用不同的权值序列进行哈夫曼树的创建,检验其编码的正确性。

如上,序列打乱,结果仍同,只是相应的,结果序列也被打乱了;

采用不同的选择方式生成相应的哈夫曼树及其编码。

如图,改变选择方式,将左右孩子变换,相应的,其编码为原来编码的反码。

2.(选做)结合模板中使用的存储结构,试着使用不同的存储形式来表示哈夫曼树及其编码。

模板应用说明

模板应用举例(结合教材图例6-2的数据,输入如下图左 ):

最后结果(如下图右显示):

  • 第二题

其实就是第一题的答案,所采用的存储形式恰好为例题6-2的形式,只是在此基础上多输出一个HT树的初态。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef char ElemType;

typedef struct{
	ElemType elem;
	int weight;
	int parent,lchild,rchild;
}HTNode,*HuffmanTree;

typedef char** HuffmanCode;


typedef struct weight
{
	char elem; 
	int  weight1; 
}Weight; // 保存字符权值
// select函数,用于选出最小的两值
void Select(HuffmanTree HT,int n,int &s1,int &s2){
	int min,i;
	// 首先选出第一个最小值
	for(i=1;i<=n;i++){
		if(HT[i].parent==0){
			min=i;
			break;
		}
	}
	for(i=min+1;i<=n;i++){
		if(HT[i].parent==0&&(HT[i].weight<HT[min].weight) ){
			min=i;
		}
	}
	s1=min;
	// 再选出第二个最小值
	for(i=1;i<=n;i++){
		if(HT[i].parent==0 && i!=s1){
			min=i;
			break;
		}
	}
	for(i=min+1;i<=n;i++){
		if(HT[i].parent==0 &&(HT[i].weight<HT[min].weight) && i!=s1){
			min=i;
		}
	}
	s2=min;
}

// 构造huffman树
void CreateHuffmantree(HuffmanTree &HT,int n,Weight* &w){
	void OutPutHuffmanTree(HuffmanTree HT,int n);
	if(n<=1)return;
	int i,s1,s2;
	int m=2*n-1;
	HT=(HuffmanTree)malloc( (m+1) *sizeof(HTNode));// 从1开始
	for(i=1;i<=n;i++){
		HT[i].elem=w[i-1].elem;
		HT[i].weight=w[i-1].weight1;
		HT[i].parent=0;
		HT[i].lchild=0;
		HT[i].rchild=0;
	}
	for(i=n+1;i<=m;i++){
		HT[i].elem='-';
		HT[i].weight=0;
		HT[i].parent=0;
		HT[i].lchild=0;
		HT[i].rchild=0;
	}
	printf("HT树的初态:\n");
	OutPutHuffmanTree(HT,n);
	for(i=n+1;i<=m;i++){
		Select(HT,i-1,s1,s2);
		HT[s1].parent=i,HT[s2].parent=i;
		if(s1<s2){
			HT[i].lchild=s1;
			HT[i].rchild=s2;           
		}
		else{
			HT[i].lchild=s2;
			HT[i].rchild=s1;           
		}
        HT[i].weight=HT[s1].weight+HT[s2].weight;
	}
 
}

void CreateHuffmanCode(HuffmanTree &HT,HuffmanCode &HC,int n){
	HC=(HuffmanCode)malloc(n*sizeof(char *) ); // 分配n个字符编码
	if(!HC)return;
	char *cd; // 作为临时存储编码的空间
	int i,c,f,start; // 临时变量
	cd = (char *)malloc(n*sizeof(char));
	cd[n-1] = '\0'; // 编码结束符,方便复制
	for(i=1;i<=n;i++){
        start=n-1;
		for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent){
			if(HT[f].lchild==c){cd[--start]='0';}
			else{cd[--start]='1';}
		}
		HC[i]=(char *)malloc( (n-start)*sizeof(char));
		strcpy(HC[i],&cd[start]);
	}
	free(cd);
}

// 输出Huffman树的权值
void OutPutHuffmanTree(HuffmanTree HT,int n){
	int j;
    printf("  结点  weight  parent  lchild  rchild");
	for (j=1; j<=2*n-1; j++){
		printf("\n%4d%8d%8d%8d%8d",j,HT[j].weight,
		HT[j].parent,HT[j].lchild, HT[j].rchild);
	}
	printf("\n");
}

// 输出Huffman树编码
void OutputHuffmanCode(HuffmanTree HT,HuffmanCode HC,int n) 
{ 
	int i; 
	printf("\n各代码的Huffman编码如下:\n"); 
	for(i=1;i<=n;i++) 
		printf("%c    %d 的编码:    %s\n",HT[i].elem,HT[i].weight,HC[i]); 
} 

int main()
{
	HuffmanTree HT;
	HuffmanCode HC;
	Weight *w;
	int n,i;
	printf("请输入Huffman树的结点个数:");
	scanf("%d",&n);
	w=(Weight *)malloc(n*sizeof(Weight));
	printf("\n注意,字符和权值之间需以空格作间隔\n\n");
	for(i=0;i<n;i++){
		printf("请输入第%d个结点的代码和其权值 : ",i+1);
		scanf("%ls%d",&w[i].elem,&w[i].weight1);
	}
    CreateHuffmantree(HT,n,w);
	CreateHuffmanCode(HT,HC,n);
	printf("HT树的末态:\n");
	OutPutHuffmanTree(HT,n);
	printf("\n");
	OutputHuffmanCode(HT,HC,n);
	return 0;
}

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是C语言实现哈夫曼编码的代码,其中包含注释: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 1000 // 定义最大编码长度 typedef struct { int weight; // 权值 int parent, lchild, rchild; // 双亲和左右孩子结点 } HTNode, *HuffmanTree; typedef char **HuffmanCode; void Select(HuffmanTree HT, int n, int *s1, int *s2) { // 在前n个结点中选择权值最小的两个结点s1和s2 int i, min; for (i = 1; i <= n; i++) { if (HT[i].parent == 0) { min = i; break; } } for (i = 1; i <= n; i++) { if (HT[i].parent == 0 && HT[i].weight < HT[min].weight) { min = i; } } *s1 = min; for (i = 1; i <= n; i++) { if (HT[i].parent == 0 && i != *s1) { min = i; break; } } for (i = 1; i <= n; i++) { if (HT[i].parent == 0 && HT[i].weight < HT[min].weight && i != *s1) { min = i; } } *s2 = min; } void CreateHuffmanTree(HuffmanTree *HT, int n) { // 由n个权值为w的结点构建哈夫曼树HT if (n <= 1) { return; } int m = 2 * n - 1; *HT = (HuffmanTree) malloc((m + 1) * sizeof(HTNode)); int i; for (i = 1; i <= m; i++) { (*HT)[i].parent = 0; (*HT)[i].lchild = 0; (*HT)[i].rchild = 0; } for (i = 1; i <= n; i++) { scanf("%d", &((*HT)[i].weight)); } int s1, s2; for (i = n + 1; i <= m; i++) { Select(*HT, i - 1, &s1, &s2); (*HT)[s1].parent = i; (*HT)[s2].parent = i; (*HT)[i].lchild = s1; (*HT)[i].rchild = s2; (*HT)[i].weight = (*HT)[s1].weight + (*HT)[s2].weight; } } void CreateHuffmanCode(HuffmanTree HT, HuffmanCode *HC, int n) { // 根据哈夫曼树HT求出n个字符的哈夫曼编码HC *HC = (HuffmanCode) malloc((n + 1) * sizeof(char *)); char *cd = (char *) malloc(n * sizeof(char)); cd[n - 1] = '\0'; int i, c, f; for (i = 1; i <= n; i++) { int start = n - 1; for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent) { if (HT[f].lchild == c) { cd[--start] = '0'; } else { cd[--start] = '1'; } } (*HC)[i] = (char *) malloc((n - start) * sizeof(char)); strcpy((*HC)[i], &cd[start]); } free(cd); } void HuffmanCoding(HuffmanTree HT, HuffmanCode HC, int n) { // 输入n个字符的权值,建立哈夫曼树HT,并求出n个字符的哈夫曼编码HC CreateHuffmanTree(&HT, n); CreateHuffmanCode(HT, &HC, n); } void HuffmanDecoding(HuffmanTree HT, int n) { // 将01序列翻译成原来的文本字符 printf("请输入01序列:\n"); char str[MAX]; scanf("%s", str); int i, c = 2 * n - 1; for (i = 0; str[i] != '\0'; i++) { if (str[i] == '0') { c = HT[c].lchild; } else { c = HT[c].rchild; } if (HT[c].lchild == 0 && HT[c].rchild == 0) { printf("%d", c); c = 2 * n - 1; } } } int main() { int n; printf("请输入字符的个数n:\n"); scanf("%d", &n); HuffmanTree HT; HuffmanCode HC; HuffmanCoding(HT, HC, n); int i; printf("各字符的哈夫曼编码如下:\n"); for (i = 1; i <= n; i++) { printf("%d %s\n", i, HC[i]); } HuffmanDecoding(HT, n); return 0; } ``` 以上是C语言实现哈夫曼编码的代码,可以根据输入的字符权值构建哈夫曼树,并输出各字符对应的哈夫曼编码。同时,可以将传输的文本转换成对应的哈夫曼编码01序列,并将哈夫曼编码01序列翻译成原来的文本字符。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值