哈夫曼编码

1.最优二叉树(哈夫曼树)
(1)结点的权:赋予叶子结点一个有意义的值
(2)结点的路径长度:从根结点到当前结点的边的个数
(3)结点的带权路径长度:WxL W:结点的权 L:结点的路径长度
(4)二叉树的带权路径长度:(wpl)一棵二叉树的所有叶子结点的带权路径长度之和 表示∑WixLi(i=1:n)
(5)最优二叉树:一棵二叉树的带权路径长度最小
2.Huffman Tree的构建
森林 F={a(9),b(3),c(6),d(4)}
(1)从森林中选取权值最小和次小的两棵二叉树,构成一棵新二叉树,并放回森林。(左子女为最小,右子女为次小)
(2)重复第一步,直至森林中只剩一棵二叉树
3.Huffman Tree实现
(1)实现链式Huffman Tree
结点:typedef struct node{
char word;
int weight;
struct node *left,*right;
}HuffNode;
(2)森林:
设有n个叶子
i>定义森林:HuffNode **F;
F=(HuffNode * *)malloc(sizeof(HuffNode *));
ii>初始化森林:for(i=0;i<n;i++){
F[i]=(HuffNode *)malloc(sizeof(HuffNode));
F[i]->left=F[i]->right=NULL;
scanf("%d",&F[i]->word);
scanf("%d",&F[i]->weight);
}
(3)实现最优二叉树

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

typedef struct node{
	char word;//名称 
	int weight;//权重 
	struct node *left,*right;
}HuffNode;

HuffNode *CreateHuffmanTree(HuffNode **F,int n)
{
	int loop,i,k1,k2;
	HuffNode *pa;
	for(loop=1;loop<n;loop++){//n个叶子结点,最多有n-1个双亲,所以只需要循环n-1次 
		for(k1=0;k1<n&&!F[k1];k1++);//将k1和k2放在不是NULL的地方
		for(k2=k1+1;k2<n&&!F[k2];k2++);
		for(i=k2;i<n;i++){//找最小、次小值的下标 
			if(F[i]){//遇到NULL说明已经结合过了  就是两个叶子已经结合成一个新的根结点了 
			//并塞入到了指针数组中较小的下标处 
				if(F[i]->weight<F[k1]->weight){
					k2=k1;
					k1=i;
				}
				else if(F[i]->weight<F[k2]->weight){
					k2=i;
				}
			}
		}
		//创建双亲
		pa=(HuffNode *)malloc(sizeof(HuffNode)); 
		pa->word='O';//标记双亲结点  也可以不要
		pa->weight=F[k1]->weight+F[k2]->weight;//将找到的最小和次小下标对应的结点权值相加构成新结点的权值
		pa->left=F[k1];//挂链 
		pa->right=F[k2]; //左子女最小 右子女次小
		F[k1]=pa;//假设F[k1]存在双亲结点
		F[k2]=NULL;//保证下次查找最小,次小值下标的正确性,避免重复计算   
	}
	return F[k1];//最后仅剩下F[k1]结点,里面存储的即为Huffman Tree的根结点 
}

void PrintHuffmanTree(HuffNode *root)
{
	//前序遍历
	if(root){
	 printf("%c:",root->word);
	 printf("%d\n",root->weight);
	 //printf("%5d",root->weight);
	 PrintHuffmanTree(root->left);
	 PrintHuffmanTree(root->right);
	}
}

int main()
{
	HuffNode *root;
	HuffNode **F;
	int i,n;
	//创建森林
	printf("请输入叶子结点个数:");
	scanf("%d",&n);
	fflush(stdin);
	F=(HuffNode **)malloc(n*sizeof(HuffNode *));
	printf("请分别输入叶子结点的名称和权重:");
	for(i=0;i<n;i++){
		F[i]=(HuffNode *)malloc(sizeof(HuffNode));
		F[i]->left=F[i]->right=NULL;
		char c=F[i]->word;
		int t=F[i]->weight;
		scanf("%c%d",&F[i]->word,&F[i]->weight);
		fflush(stdin);
		//scanf("%d",&F[i]->weight);
	}
	root=CreateHuffmanTree(F,n);//创建哈夫曼树
	PrintHuffmanTree(root);//输出哈夫曼树 
	return 0;
}

4.以数组形式实现Huffman Tree及其编码
(1)结构体数组
类型:typedef struct{
char word;
int weight;
int left,right,parent;
int *code;
}HuffNode;
(2)声明结构体数组
HuffNode *F;
F=(HuffNode )malloc((2n-1)*sizeof(HuffNode));
(3)初始化
for(i=0;i<n;i++){
scanf("%c",&h);
F[i].word=ch;
scanf("%d",&w);
F[i].weight=w;
F[i].left=F[i].right=F[i].parent=-1;
}

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

typedef struct{
	char word;//名称 
	int weight;//权重 
	int left,right,parent;
	int *code;//执向存放哈夫曼编码的数组的指针 
}HuffNode;

void CreateHuffmanTree(HuffNode *F,int n)
{
	int loop;
	int k1,k2,i;
	for(loop=0;loop<n-1;loop++){//循环遍历n-1次,生成n-1个双亲结点 
		for(k1=0;k1<n+loop&&F[k1].parent!=-1;k1++);//k1,k2定位到没有双亲的位置上 
		for(k2=k1+1;k2<n+loop&&F[k2].parent!=-1;k2++);
		for(i=k2;i<n+loop;i++){//循环遍历找出最小、次小值的下标 
			if(F[i].parent==-1){//说明其还未与其他叶子合并,否则直接跳过 
				if(F[i].weight<F[k1].weight){
					k2=k1;
					k1=i;
				}
				else if(F[i].weight<F[k2].weight){
					k2=i;
				}
			}
		}
		F[i].word='x';//标记名称 
		F[i].weight=F[k1].weight+F[k2].weight;//双亲结点等于两个叶子结点相加 
		F[i].left=k1;//逻辑上挂链,即指向 
		F[i].right=k2;
		F[i].parent=-1;//对于新合成的结点parent赋初值,即-1 
		F[k1].parent=F[k2].parent=i;//修改子女的parent域 
	}
}

void CreateHuffmanCode(HuffNode *F,int n)
{
	int c,pa,i;
	int *p;
	for(i=0;i<n;i++){//遍历当前n个叶子结点 
		F[i].code=p=(int *)malloc(n*sizeof(int));//分配n个空间,p[0]空间作为岗哨
		p[0]=0;
		c=i;
		while(F[c].parent!=-1){//不等于-1,说明其不为根结点,则进入循环,持续判断并求编码值赋予存储编码的数组空间 
			pa=F[c].parent;
			if(F[pa].left==c){//pa所指的数组的left域等于c,说明其为它的左子女,所以编码为0 
				p[++p[0]]=0;
			}
			else{//说明其为它的右子女,所以编码为1 
				p[++p[0]]=1;
			} 
			c=pa; //c重新指向其双亲结点 
		} 
	}
}

void PrintHuffmanCode(HuffNode *F,int n)
{
	for(int i=0;i<n;i++){//循环遍历它的n个叶子结点 
		//输出其对应的哈夫曼编码
		printf("%c:",F[i].word);//输出对应字符 
		for(int j=F[i].code[0];j>0;j--){//循环输出对应字符的哈夫曼编码,即倒着输出数组岗哨到1的值
		//对应相应叶子结点的根到叶子结点的哈夫曼编码 
			printf("%d",F[i].code[j]); 
		} 
		printf("\n");
	}
}

int main()
{
	HuffNode *F;
	int n,i;
	char ch;
	int w;
	printf("请输入叶子结点个数:");
	scanf("%d",&n);
	fflush(stdin);
	printf("请输入叶子结点的名称和权值:");
	//创建森林
	F=(HuffNode *)malloc((2*n-1)*sizeof(HuffNode));//n个叶子结点,生成的哈夫曼树中,最多有2n-1个结点 
	for(i=0;i<n;i++){
	 		scanf("%c",&F[i].word);
	 		scanf("%d",&F[i].weight);
	 		fflush(stdin);
	 		F[i].left=F[i].right=F[i].parent=-1;
	 	}
	//创建哈夫曼树
	CreateHuffmanTree(F,n);
	//创建HuffmanCode
	CreateHuffmanCode(F,n);
	//输出
	PrintHuffmanCode(F,n);
	return 0; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值