贪心算法求解哈弗曼编码

哈夫曼编码是广泛地用于数据文件压缩的十分有效的编码方法。其压缩率通常在20%~90%之间。哈夫曼编码算法用字符在文件中出现的频率表来建立一个用0,1串表示各字符的最优表示方式。

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

typedef struct {
	int weight;
	int parent,lchild,rchild;  //儿子节点的parent存放父节点的下标  父节点的lchild和rchild存放儿子节点的下标
}HTNode,*HuffmanTree;  //动态分配数组,存储赫夫曼树
typedef char **HuffmanCode;//动态分配数组存储赫夫曼编码表

//从树种选择两个比较小的树
void select(HuffmanTree Ht,int n,int &s1,int &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)
			{
			  if(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 && i!=s1)	
			{
			  if(Ht[i].weight<Ht[min].weight) 
				  min=i;
			}
		 }
		 s2=min;	
}

  // w存放n个字符的权值(均>0),构造哈夫曼树HT,并求出n个字符的哈夫曼编码HC
void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n) {
  int i,  m, s1, s2, start;
  char *cd;
  int c, f;

  if (n<=1) return; 
  m = 2 * n - 1;  //共需要m个节点
  HT = (HuffmanTree)malloc((m+1) * sizeof(HTNode));  // 0号单元未用
  for (i=1; i<=n; i++) { //初始化前n个节点
    HT[i].weight=w[i-1];
    HT[i].parent=0;
    HT[i].lchild=0;
    HT[i].rchild=0;
  }
  for (i=n+1; i<=m; i++) { //初始化n+1到m个节点
    HT[i].weight=0;
    HT[i].parent=0;
    HT[i].lchild=0;
    HT[i].rchild=0;
  }

  for (i=n+1; i<=m; i++) {  // 建哈夫曼树
    // 在HT[1..i-1]中选择parent为0且weight最小的两个结点,
    // 其序号分别为s1和s2。
    select(HT, i-1, s1, s2);  
    HT[s1].parent = i;  HT[s2].parent = i;  //改变s1 和s2的节点的父节点的值
    HT[i].lchild = s1;  HT[i].rchild = s2;
    HT[i].weight = HT[s1].weight + HT[s2].weight;
  }

  //--- 从叶子到根逆向求每个字符的哈夫曼编码 ---
  HC=(HuffmanCode)malloc((n+1)*sizeof(char *));  //分配n个编码的头指针
  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)  //获得parent中值并判断值是否为零 依次后移
      // 从叶子到根逆向求编码
      if (HT[f].lchild==c) cd[--start] = '0';
      else cd[--start] = '1';
    HC[i] = (char *)malloc((n-start)*sizeof(char)); //为第i个编码分配空间
         // 为第i个字符编码分配空间
    strcpy(HC[i], &cd[start]);    // 从cd复制编码(串)到HC
//	puts(HC[i]);
  }
  free(cd);   // 释放工作空间
} // HuffmanCoding

void putout(HuffmanCode HC,char c[],int n){
	int i;
	printf("字符对应的编码分别为:\n");
	for(i=0;i<n;i++){
		printf("%c ",c[i]);
		puts(HC[i+1]);
		printf("\n");
	}
}

int main(){
	int n,i;
	char *c=NULL;
	int *w=NULL;
	HuffmanTree HT;
	HuffmanCode HC;
	printf("请输入共有几个字符:\n");
	scanf("%d",&n);
	fflush(stdin);
    c=(char *)malloc(sizeof(char)*(n)); //存放字符分配空间
	w=(int *)malloc(sizeof(int)*(n));   //存放权值分配空间
	for(i=0;i<n;i++){ 
		printf("请输入第%d个字符和权值:",i+1);
		scanf("%c %d",c+i,w+i);
	    fflush(stdin);
		printf("\n");
	}
	HuffmanCoding(HT,HC,w,n);
    putout(HC,c,n);
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值