C语言创建哈夫曼树并计算哈夫曼编码

题目

在这里插入图片描述

解答
	#include<stdio.h>
	#include<stdlib.h>
	#include<string.h>
	
	#define MAX_TREE_SIZE 100	//树的最大结点数
	
	/*测试数据:5 2 5 7 9 13*/
	
	/*哈夫曼树类型定义*/
	typedef struct{
		int weight;  //权值 
		int parent;  //双亲索引				
		int lchild;  //左孩子索引 
		int rchild;  //右孩子索引
	}HTNode;
	
	HTNode HT[MAX_TREE_SIZE];  //静态数组存储哈夫曼树
	typedef char* HCNode;
	typedef HCNode* HuffmanCode;   //动态分配数组存储哈夫曼编码表 
	
	int N; //全局变量,哈夫曼树叶子结点个数
	
	/*选出还未编入树的最小结点所在下标*/
	/*【从下标为0-->i中的结点选】*/
	int findMin(int i){
		int min=INT_MAX; //存储最小结点的权值,初始为INT_MAX
		int tag=-1; //标记最小结点所在下标
		int j;
		for(j=1;j<=i;j++){ 
			if(HT[j].parent==0){ //说明该结点还未编入树
				if(HT[j].weight<min){ //更新最小结点以及它所在的下标
					min=HT[j].weight;
					tag=j;
				}
			}
		}
		return tag;
	}
	
	/*建立哈夫曼树并统计该哈夫曼树的结点个数*/
	int CreateHuffmanTree(HTNode HT[]){
		int i;
		int count;  //统计哈夫曼树结点个数
		int min1, min2;
	
		printf("请录入哈夫曼树叶子结点个数→");
		scanf("%d", &N); 	
		printf("请依次录入各叶子结点的权值→ "); 
		for(i=1; i<=N; i++){    //0号单元弃用
			scanf("%d", &HT[i].weight); 
			HT[i].parent = 0;
			HT[i].lchild = 0;
			HT[i].rchild = 0; 
		}
		i--; //i回退【指示最后一个叶子结点所在的位置】
	
		/*每次从未编入树的结点中选出两个最小的,然后确定它们的父结点*/
		while(1){
			min1=findMin(i); //选出还未编入树的最小结点所在下标【从下标为0-->i中的结点选】
			/*假设父结点下标依次存放在数组中,每出现一个新的父结点,i++*/
			HT[min1].parent=i+1; //将父结点的位置赋给最小结点【此时parent已经不为0了,HT[min1]已被编入树】
	
			min2=findMin(i); //选出还未编入树的次小结点所在下标【由于HT[min1]已被编入树了,因此再次选的时候选的是第2小的】
			if(min2==-1){ //如果得到的结果是-1,说明除了根结点以外的所有结点都已经被编入树了
				HT[i].parent=0; //将根结点的parent置为0【将根结点编入树】
				break;   //哈夫曼树构造完毕,退出循环
			}
			else
				HT[min2].parent=i+1; //将父结点的位置赋给次小结点【此时parent已经不为0了,HT[min2]已被编入树】
	
			/*此时i+1的位置就是新生成结点所在的位置【即min1和min2的父结点所在位置】*/
			/*给新生成结点赋属性*/
			HT[i+1].parent=0; //表示该结点还未编入树
			HT[i+1].lchild=min1; //其左孩子是最小的
			HT[i+1].rchild=min2; //其右孩子是次小的
			HT[i+1].weight=HT[min1].weight+HT[min2].weight; //权值为左右孩子的权值之和
			i++; //i++,指向新结点所在位置
		}
	
		printf("此哈夫曼树的结点个数为%d\n",i); //由于哈夫曼数组的下标是从1开始的,因此这里是i
	} 
	
	/*逆序计算哈夫曼编码值*/
	int HuffmanCodeing(HTNode HT[], HuffmanCode *HC){
		char *code;
		int n, i;
		int start, c, f;
		
		n = N;	//叶子结点个数 
		
		*HC = (HuffmanCode)malloc((n+1)*sizeof(HCNode));
		if(!(*HC))
			exit(0);
		
		code = (char*)malloc(n*sizeof(char));
		if(!code)
			exit(0);	
		
		code[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)
					code[--start] = '0';
				else
					code[--start] = '1';
			}
			
			(*HC)[i] = (char*)malloc((n-start)*sizeof(char));
			
			strcpy((*HC)[i], &code[start]);	 //从start开始复制 
		}
		
		free(code);
	}
	
	/*展示哈夫曼树*/
	void ShowHuffmanTree(HTNode HT[]){
		int i;
		printf(" *order weight parent lchild rchild\n");
		for(i=1; i<=2*N-1; i++){
			printf("   %2d    %4d    %2d     %2d     %2d\n", i, HT[i].weight, HT[i].parent, HT[i].lchild, HT[i].rchild);
		}
	}
	
	/*打印哈夫曼编码*/
	void ShowHuffmanCode(HTNode HT[], HuffmanCode HC){
		int i;
		printf("*order weight   哈夫曼编码\n");
		for(i=1; i<=N; i++)
			printf("  %2d   %4d  ──→  %-14s\n", i, HT[i].weight, HC[i]);	
	}
	
	/*计算树的带权路径长度*/
	int WPL(HTNode HT[], HuffmanCode HC){
		int i,wpl=0;
		for(i=1; i<=N; i++)
			wpl += HT[i].weight*strlen(HC[i]);
		return wpl;
	}
	
	int main(){
		HuffmanCode HC;
	
		printf("创建哈夫曼树 HT ...\n");
		CreateHuffmanTree(HT);
		
		printf("展示哈夫曼树 HT = \n");
		ShowHuffmanTree(HT);
	
		printf("计算哈夫曼编码 HC ...\n");		
		HuffmanCodeing(HT, &HC);
		printf("\n");
		
		printf("展示哈夫曼编码 HC = \n");	
		ShowHuffmanCode(HT, HC);
		printf("\n");
	
		printf("哈夫曼树的带权路径长度 WPL = %d\n",WPL(HT, HC));	
		printf("\n");
	
		return 0;
	}
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值