哈弗曼编码

Description

写一个哈夫曼码的编/译码系统,要求能对要传输的报文进行编码和解码。构造哈夫曼树时,权值小的放左子树,权值大的放右子树,编码时右子树编码为1,左子树编码为0。

Input

输入表示字符集大小为n(n <= 100)的正整数,以及n个字符和n个权值(正整数,值越大表示该字符出现的概率越大);输入串长小于或等于100的目标报文。

Output

经过编码后的二进制码,占一行;
以及对应解码后的报文,占一行;
最后输出一个回车符

  • Sample Input 
    5 a b c d e 12 40 15 8 25
    bbbaddeccbbb
  • Sample Output
    00011111110111010110110000
    bbbaddeccbbb

这个题费了我一个多星期的时间去debug,竟然是数据没有初始化,气死我了,写的思路有点乱



#include
#include
#include

int pc = 1;

typedef struct htnode //哈夫曼树节点的结构
{
	int weight;//权值
	int parent, lchild, rchild;//记录相应的位置
	int flag;//记录代码0/1
}htnode;

typedef struct httree 
{
	htnode ht[3000];//数组为存储结构
	int root; //树根在数组中的位置
}phtree;

void select(phtree* pht,int pos,int *x1,int *x2)//选择最小的两个数
{
	int m1, m2;
	m1 = m2 = 10000;
	for(int i = 1;i < pos;i++)
	{
		if(pht->ht[i].weight < m1 && pht->ht[i].parent == 0)
		{ 
			m2 = m1;
			*x2 = *x1;
			m1 = pht->ht[i].weight;
			*x1 = i;  // x1 = &i??????????????????????????????????
		}
		else if(pht->ht[i].weight < m2 && pht->ht[i].parent == 0 && pht->ht[i].weight > m1)
		{
			m2 = pht->ht[i].weight;
			*x2 = i;  // 参数改为&x
		}
	}
}

phtree *huffman(int n,int *w)
{
	phtree* pht;
	int i, x1, x2;
	pht = (phtree* )malloc(sizeof(phtree));
	
	//将用不到的空间初始化
	pht->ht[0].flag = 2;
	pht->ht[0].lchild = 0;
	pht->ht[0].rchild = 0;
	pht->ht[0].parent = 0;
	pht->ht[0].weight = 0;
	for(i = 2*n;i < 3000;i++)
	{
		pht->ht[i].flag = 2;
		pht->ht[i].lchild = 0;
		pht->ht[0].rchild = 0;
		pht->ht[0].parent = 0;
		pht->ht[0].weight = 0;
	}
	//n个字符需要2n-1个节点空间
	//置初态
	for(i = 1;i <= 2*n-1;i++) 
	{
		pht->ht[i].lchild = 0;
		pht->ht[i].rchild = 0;
		pht->ht[i].parent = 0;
		pht->ht[i].flag = 2;
		if(i <= n)
		{
			pht->ht[i].weight = w[i];//权值输入
		}
		else
		{
			pht->ht[i].weight = 0;
		}
	}
	

	for(i = 1;i < n;i++)//创建哈夫曼树
	{
		select(pht,n+i,&x1,&x2);
		pht->ht[x1].parent = n+i;
		pht->ht[x1].flag = 0;
		pht->ht[x2].parent = n+i;
		pht->ht[x2].flag = 1;
		pht->ht[n+i].weight = pht->ht[x1].weight + pht->ht[x2].weight;
		pht->ht[n+i].lchild = x1;//权值小的左子树
		pht->ht[n+i].rchild = x2;
		pht->root = n+i;
	}
	return pht;
}

void code(phtree *t,int n,int pcode[][100])//进行编码(注意得到的是倒序)
{
	int i = 1;
	htnode node;
	node = t->ht[pc];
	while(node.parent != 0)
	{
		pcode[pc][i] = node.flag;
		node = t->ht[node.parent];
		i++;
	}
	pc++;
}

void output(int pcode[][100],int n,char *x)
{
	int i, j, k, cnt;
	int code[100][100];
	for(i =0;i < 100;i++)
	{
		for(j = 0;j < 100;j++)
		{
			code[i][j] = -1;
		}
	}
	for(i = 1;i <= n;i++)//将编码正序
	{
		for(cnt = 1;pcode[i][cnt+1] == 1 || pcode[i][cnt+1] == 0;cnt++);
		k = cnt;
		for(j = 1;j<= k;j++)
		{
			code[i][j] = pcode[i][cnt--];
		}
	}
	/*
	for(i = 1;i <= n;i++)
	{
		printf("%c  ",x[i]);
		for(int j = 1;pcode[i][j] == 0 || pcode[i][j] == 1;j++)
		{
			printf("%d",pcode[i][j]);
		}
		printf("\n");
	}
	
	for(i = 1;i <= n;i++)
	{
		printf("%c  ",x[i]);
		for(int j = 1;code[i][j] == 0 || code[i][j] == 1;j++)
		{
			printf("%d",code[i][j]);
		}
		printf("\n");
	}
*/
	char s[100], c;//待编码字符串
	scanf("%s",s);
	int f = strlen(s);
	for(i = 0;i <= f;i++)
	{
		for(j = 1;j <= n;j++)  //将每一个字符与已知的进行比较,相同的则输出相应编码
		{
			if(s[i] == x[j])
			{
				for(k = 1;code[j][k] == 0 || code[j][k] == 1;k++)
				{
					printf("%d",code[j][k]);
				}
			}
		}
	}
	
	printf("\n%s\n",s);
}

int main()
{
	int i, n, cnt = 1;
	char c;
	int w[101];//权值
	char s[101];//字符
	int pcode[100][100];//存储倒哈夫曼码
	for(i = 0;i < 100;i++)
	{
		for(int j = 0;j < 100;j++)
		{
			pcode[i][j] = -1;
		}

	}
	scanf("%d",&n);
	while(1)
	{
		scanf("%c",&c);
		if(cnt == n+1)
		{
			break;
		}
		else if(c != ' ')
		{
			s[cnt++] = c;
		}
	}
	for(i = 1;i <= n;i++)
	{
		scanf("%d",&w[i]);
	}
	phtree* pht;
	pht = huffman(n,w);
	for(i = 1;i <= n;i++)
	{
		code(pht,n,pcode);
	}
	output(pcode,n,s);
	return 0;
}

你可能感兴趣的:(数据结构,二叉树)