编程问题:问题 A: DS_6.13 给定权值,哈弗曼编码、译码(by Yan)

1 篇文章 0 订阅

问题 A: DS_6.13 给定权值,哈弗曼编码、译码(by Yan)

时间限制: 20 Sec  内存限制: 256 MB
提交: 500  解决: 346
[提交][状态][讨论版]

题目描述

假设某通信报文的字符集由A,B,C,D,E,F这6个字符组成,它们在报文中出现的频度(频度均为整数值)。
(1)构造一棵哈弗曼树,依次给出各字符编码结果。
(2)给字符串进行编码。
(3)给编码串进行译码。

规定:
构建哈弗曼树时:左子树根结点权值小于等于右子树根结点权值。
生成编码时:左分支标0,右分支标1。

输入

第一行:依次输入6个整数,依次代表A,B,C,D,E,F的频度,用空格隔开。
第二行:待编码的字符串
第三行:待译码的编码串

输出

前6行依次输出各个字符及其对应编码,格式为【字符:编码】(冒号均为英文符号)
第7行:编码串
第8行:译码串

样例输入

3 4 10 8 6 5 BEE 0010000100111101

样例输出

A:000 B:001 C:10 D:01 E:111 F:110 001111111 BADBED

 

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

#define N	 6
#define M    11

typedef char *Huffmancode[6];

typedef struct
{
	int weight;
	int parent,Lchild,Rchild;
}HTNode,HuffmanTree[M+1];				//零号单元不用

void select(HuffmanTree ht, int n, int *s1, int *s2){		/*挑选哈夫曼书前n项中权值
															                        最小且parent不为0的两个值的下标*/
	int c[30];

	int i,j,h;

	int cut = 0;

	for(i=0; i<30; i++)c[i] = 0 ;

	for(i=1; i<=n; i++){
		if( ht[i].parent==0 ){
			c[cut] = ht[i].weight;
			cut++;
		}
	}

	for(i=0; i<cut; i++){						//冒泡排序
		for(j=0; j<cut-i-1; j++){
			if( c[j]>c[j+1] ){
				h = c[j];
				c[j] = c[j+1];
				c[j+1] = h;
			}
		}
	}
	
	for(i=1; i<=n; i++){
		if(c[0]==0 || c[1]==0){
			printf("error\n") ;
			return ;
		}

		if( c[0]==ht[i].weight )
			*s1 = i;
		if( c[1]==ht[i].weight )
			*s2 = i;
	}
}

void CreatHuffmanTree(HuffmanTree ht, int w[], int n){				//创建哈夫曼树
	int m = 2*n-1;
	int s1,s2;
	int i;

	for(i=0; i<=n; i++){
		ht[i].weight = w[i];
		ht[i].Lchild = 0;
		ht[i].Rchild = 0; 
		ht[i].parent = 0;
	}

	for(i=n+1; i<=m; i++){
		ht[i].weight = 0; 
		ht[i].Lchild = 0; 
		ht[i].Rchild = 0;
		ht[i].parent = 0;
	}

	for(i=n+1; i<=m; i++){
		select(ht, i-1, &s1, &s2);
		//Print(ht);
		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 ;
	}
}

void CrtHuffmanCodel(HuffmanTree ht, Huffmancode hc, int n){				//哈夫曼树编码
	char *cd;
	int start;
	int i,c,p;
	cd = (char *)malloc(n * sizeof(char));
	cd[n-1] = '\0';
	for(i=1; i<=n; i++){
		start = n-1; 
		c = i;
		p = ht[i].parent;
		while (p!=0){
			--start;
			if(ht[p].Lchild==c){
				cd[start] = '0';
			}
			else 
				cd[start] = '1';
			c = p;					
			p = ht[p].parent;
		}
		hc[i] = (char *)malloc((n - start) * sizeof(char));
		strcpy(hc[i], &cd[start]);
	}
	free(cd);
}

void print(Huffmancode hc){						//输出哈夫曼树编码
	int i;
		
	for(i=1; i<=6; i++){
		switch(i){
		case 1:printf("A:%s",hc[1]);break;
		case 2:printf("B:%s",hc[2]);break;
		case 3:printf("C:%s",hc[3]);break;
		case 4:printf("D:%s",hc[4]);break;
		case 5:printf("E:%s",hc[5]);break;
		case 6:printf("F:%s",hc[6]);break;
		}
		printf("\n");
	}
}

void println(HuffmanTree ht, int p){			//输出p为叶子节点时的译码信息
		switch(p){
		case 1:printf("A");break;
		case 2:printf("B");break;
		case 3:printf("C");break;
		case 4:printf("D");break;
		case 5:printf("E");break;
		case 6:printf("F");break;
		}
}

void TransHuffmancodel(HuffmanTree ht, char *c){	//哈弗满树译码
	int i,p,d; 

	p = M;

	for(i=0; c[i]!='\0'; i++){
		if (c[i]=='0'){
			p = ht[p].Lchild;
			if(ht[p].Lchild==0 && ht[p].Rchild==0){
				println(ht, p);
				p = M;
			}
		}
		if (c[i]=='1'){
			p = ht[p].Rchild;
			if(ht[p].Lchild==0 && ht[p].Rchild==0){
				println(ht, p);
				p = M;
			}
		}
	}
}

int main(){

	int i,j;

	HuffmanTree ht ;

	int w[N+1];

	for(i=1; i<=6; i++){
		scanf("%d",&w[i]);
	}

	CreatHuffmanTree(ht, w, 6) ;
	
	Huffmancode hc;

	CrtHuffmanCodel(ht, hc, 6);
	


	char s[6], c[100];

	scanf("%s",s);

	scanf("\n%s",c);

	print(hc);
	
	for(i=0; i<strlen(s); i++){
		switch(s[i]){
		case 'A':printf("%s",hc[1]);break;
		case 'B':printf("%s",hc[2]);break;
		case 'C':printf("%s",hc[3]);break;
		case 'D':printf("%s",hc[4]);break;
		case 'E':printf("%s",hc[5]);break;
		case 'F':printf("%s",hc[6]);break;
		}
	}
	printf("\n");

	TransHuffmancodel(ht, c);
	
	printf("\n");

	return 0;
}​

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值