哈夫曼编码(贪心)

来源:互联网 发布:ie9浏览器mac官方下载 编辑:程序博客网 时间:2024/05/03 16:43

算法设计例题:哈夫曼编码(贪心)

memory limit: 32768KB    time limit: 1000MS

accept: 4    submit: 8

Description

给定字符出现的频率,构造哈夫曼编码。
设定哈夫曼树左子树编码为0,右子树编码为1。

Input

输入的第一行为测试样例的个数T( T <= 100 ),接下来有T个测试样例。每个测试样例的第一行是一个整数n( n <= 65 ),表示有n个字符需要编码。接下来n行,每行为一个字符c和一个整数w,分别表示字符的标识以及该字符出现的频率。

Output

对应每个测试样例输出一行,格式为"Case #:",其中'#'表示第几个测试样例(从1开始计),接下来n行,格式为"c w x",其中c为字符标识,w为该字符的频率,x为该字符的哈夫曼编码,以读入的字符顺序依次输出。

Sample Input

1
6
a 45
b 13
c 12
d 16
e 9
f 5

Sample Output

Case 1:
a 45 0
b 13 101
c 12 100
d 16 111
e 9 1101
f 5 1100

源码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
 
struct htnode
{
    int weight;
    int parent,lchild,rchild;
}ht[200];
char hc[100][100];
char C[100][2];
int w[100];
 
//选择两个parent为0,且weight最小的结点s1和s2
void select(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;
}
 
//构造哈夫曼树ht,w存放已知的n个权值
void CrtHuffmanTree(int n)
{
    int m,i,s1,s2;
    m=2*n-1;
    memset(ht,0,sizeof(ht));
    for(i=1;i<=n;++i)
    {
        ht[i].weight=w[i];
    }
    for(i=n+1;i<=m;++i)
    {
        select(i-1,s1,s2);
        ht[s1].parent=i;
        ht[s2].parent=i;
        ht[i].lchild=s1;
        ht[i].rchild=s2;
        ht[i].weight=ht[s1].weight+ht[s2].weight;
    }
}
 
//从叶子结点到根,逆向求每个叶子结点对应的哈夫曼编码
void CrtHuffmanCode(int n)
{
    char cd[100];
    int a[100];
    int i,start,p;
    int c;
    cd[n-1]='\0';
    for(i=1;i<=n;++i)
    {
       a[i]=0;
       start=n-1;
       for(c=i,p=ht[i].parent;p!=0;c=p,p=ht[p].parent)
       {
           if(ht[p].lchild==c)
           {
               cd[--start]='0';
               a[i]++;
           }
           else
           {
               cd[--start]='1';
               a[i]++;
           }
       }
       strcpy(hc[i],&cd[start]);
   }
    for(i=1;i<=n;++i)
    {
       printf("%s %d %s\n",C[i],w[i],hc[i]);
   }
}
 
int main()
{
   //freopen("data.in","r",stdin);
   //freopen("data.out","w",stdout);
   int T,cas=1;
   scanf("%d",&T);
   while(T--)
   {
       int i,n;
       scanf("%d",&n);
       for(i=1;i<=n;++i)
       {
           scanf("%s %d",C[i],&w[i]);
       }
       printf("Case %d:\n",cas++);
       CrtHuffmanTree(n);
       CrtHuffmanCode(n);
   }
   return 0;
}


-----------------
// 哈夫曼编码(算法)


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


typedef char *HuffmanCode;  //动态分配数组,存储哈夫曼编码


typedef struct
{
 unsigned int weight;  //用来存放各个结点的权值
 unsigned int parent,LChild,RChild;  //指向双亲、孩子结点的指针
} HTNode, *HuffmanTree;  //动态分配数组,存储哈夫曼树


//选择两个parent为0,且weight最小的结点s1和s2
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;
}


//构造哈夫曼树ht。w存放已知的n个权值
void CrtHuffmanTree(HuffmanTree *ht,int *w,int n)
{
 int m,i,s1,s2;
 m=2*n-1;
 *ht=(HuffmanTree)malloc((m+1)*sizeof(HTNode));
 for(i=1; i<=n; i++)  //1--n号存放叶子结点,初始化
 {
  (*ht)[i].weight=w[i];
  (*ht)[i].LChild=0;
  (*ht)[i].parent=0;
  (*ht)[i].RChild=0;
 }
 for(i=n+1; i<=m; i++)
 {
  (*ht)[i].weight=0;
  (*ht)[i].LChild=0;
  (*ht)[i].parent=0;
  (*ht)[i].RChild=0;
 } //非叶子结点初始化
 printf("\nHuffmanTree: \n");
 for(i=n+1; i<=m; i++)   //创建非叶子结点,建哈夫曼树
 { //在(*ht)[1]~(*ht)[i-1]的范围内选择两个parent为0
  //且weight最小的结点,其序号分别赋值给s1、s2
  Select(ht,i-1,&s1,&s2);
  (*ht)[s1].parent=i;
  (*ht)[s2].parent=i;
  (*ht)[i].LChild=s1;
  (*ht)[i].RChild=s2;
  (*ht)[i].weight=(*ht)[s1].weight+(*ht)[s2].weight;
  printf("%d (%d, %d)\n",(*ht)[i].weight,(*ht)[s1].weight,(*ht)[s2].weight);
 }
 printf("\n");
} //哈夫曼树建立完毕


//从叶子结点到根,逆向求每个叶子结点对应的哈夫曼编码
void CrtHuffmanCode(HuffmanTree *ht, HuffmanCode *hc, int n)
{
 char *cd;
 int i,start,p;
 unsigned int c;
 hc=(HuffmanCode *)malloc((n+1)*sizeof(char *));  //分配n个编码的头指针
 cd=(char *)malloc(n*sizeof(char));  //分配求当前编码的工作空间
 cd[n-1]='\0';  //从右向左逐位存放编码,首先存放编码结束符
 for(i=1; i<=n; i++)  //求n个叶子结点对应的哈夫曼编码
 {
  start=n-1;  //初始化编码起始指针
  for(c=i,p=(*ht)[i].parent; p!=0; c=p,p=(*ht)[p].parent)  //从叶子到根结点求编码
   if( (*ht)[p].LChild==c) cd[--start]='0';  //左分支标0
   else cd[--start]='1';  //右分支标1
  hc[i]=(char *)malloc((n-start)*sizeof(char));  //为第i个编码分配空间
  strcpy(hc[i],&cd[start]);
 }
 free(cd);
 for(i=1; i<=n; i++)
  printf("HuffmanCode of %3d is %s\n",(*ht)[i].weight,hc[i]);
 printf("\n");
}


void main()
{
 HuffmanTree HT;
 HuffmanCode HC;
 int *w,i,n,wei,m;


 printf("\nn = " );
 scanf("%d",&n);
 w=(int *)malloc((n+1)*sizeof(int)); 
 printf("\ninput the %d element's weight:\n",n); 
 for(i=1; i<=n; i++)
 { 
  printf("%d: ",i); 
  fflush(stdin);
  scanf("%d",&wei);
  w[i]=wei;
 }
 CrtHuffmanTree(&HT,w,n);
 CrtHuffmanCode(&HT,&HC,n);
}

参考资料:http://coolshell.cn/articles/7459.html

原创粉丝点击