第六天-------哈夫曼编码 附源码

 一、 目的

1.掌握哈夫曼树和哈夫曼编码的基本思想和算法的程序实现。

二、内容

1、内容

(1)修理牧场:农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要N块木头,每块木头长度为整数L​i​​个长度单位,于是他购买了一条很长的、能锯成N块的木头,即该木头的长度是L​i​​的总和。

但是农夫自己没有锯子,请人锯木头的酬金跟这段木头的长度成正比。为简单起见,不妨就设酬金等于所锯木头的长度。例如,要将长度为20的木头锯成长度为8、7和5的三段,第一次锯木头花费20,将木头锯成12和8;第二次锯木头花费12,将长度为12的木头锯成7和5,总花费为32。如果第一次将木头锯成15和5,则第二次锯木头花费15,总花费为35(大于32)。

请编写程序帮助农夫计算将木头锯成N块的最少花费。

首先输入一个正整数N(N≤10​4​​),表示要将木头锯成N块。接着给出N个正整数Li(Li≤50),表示每段木块的长度。输出一个整数,即将木头锯成N块的最少花费。

例如:

输入:

8

4 5 1 2 1 3 1 1

输出:

49

*(2)压缩软件:

给定一篇文章,只含有英文大小写字母和空格,以.txt格式存储,统计该文件中各种字符的频率,对各字符进行Huffman编码,将该文件翻译成Huffman编码文件,再将Huffman编码文件翻译成源文件。

 

2、主要数据类型与变量

必要时,可对数据类型和变量进一步解释或说明,增加可读性

1.参考类型定义   //双亲孩子表示法      

        typedef struct {

            unsignedint  weight;

            unsigned int  parent, lchild, rchild;

        } HTNode, *HuffmanTree;      //动态分配数组存储哈夫曼树

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

 

3、算法思想描述

构建哈夫曼树,获得哈夫曼编码。

三、系统测试

1、测试方案

测试,最开始并没有用读入文件的操作,只是从控制台输入几个字符,如下:

 

后来,在别人的帮助下开始读取文件的操作,并成功运行。

2、测试结果

第一次读取文件的时候,在命令行上并没有出现哈夫曼编码,只是将1.txt文件中的字符串输出了。

 

不过在1.txt中已经将哈夫曼编码写入

 

第二次执行程序的时候,直接在命令行中输出了字符串的编码

 

文件中又被写入了一次

 

 

附:程序源代码

 

 

源代码:

DS.h

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <math.h>

 

#define TRUE 1

#define FALSE 0

#define OK 1

#define ERROR 0

 

typedef int Status;

 

HfmTree.h

 

#include "DS.h"

 

typedef int TElemType;

 

typedef struct {

    int  weight;                  //权值

    int  parent, lchild, rchild;  //有无父节点,左孩子,右孩子

} HTNode, *HuffmanTree;            //动态分配数组存储哈夫曼树

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

 

void HuffmanCoding(HuffmanTree&HT,HuffmanCode &HC,int *w, int n);   //构建哈夫曼树,求出哈夫曼编码

void Select(HuffmanTree HT,int n,int&s1, int &s2);                  //选择两个权值最小的节点

void outputfile(HuffmanCode HC,int n,char*a);                        //字符输出

void inputfile(char *str);                                            //字符读入

void Huffmans (int w[],char *str,int&n,char*a);                      //统计文件中各字符的个数

 

main.cpp

 

#include "HfmTree.h"

 

int main()

{

   HuffmanTree HT;

   HuffmanCode HC;      //定义哈夫曼树与哈夫曼编码

   char str[99999],a[60];

   int w[60];

   int n;

 

   inputfile(str);           //读入字符串

   printf("%s\n",str);      //将读取到的字符串输出

   Huffmans(w,str,n,a);      //统计该字符串中各字符的次数

   HuffmanCoding(HT,HC,w,n); //对这些字符进行编码

   printf("\n");

   outputfile(HC, n,a);      //将哈夫曼编码输出带文件中

   return 0;

}

 

HfmTree.cpp

#include "HfmTree.h"

 

void HuffmanCoding(HuffmanTree&HT,HuffmanCode &HC,int *o, int n){

  char * cd;

  int m ,c,f,k=0,start,i,s1,s2;

  int w[60];

  for(i=0;i<60;i++){

   w[i] = 0;

   }

  for(i = 0; i<60; i++){

   if(o[i] != 0){

      w[k] = o[i];

      k++;

    }

   }

 

  if(n<-1) return;

   m= 2 * n - 1;

   HT= (HuffmanTree)malloc((m+1)*sizeof(HTNode));

  for( i=1; i<=n; ++i) {

      HT[i].weight=w[i-1] ;HT[i].parent = 0; HT[i].lchild = 0; HT[i].rchild =0;

    }

 for(;i<=m;++i) {

    

     HT[i].weight=0 ;HT[i].parent = 0; HT[i].lchild = 0; HT[i].rchild = 0;

    }

  for(i =n+1; i<=m; ++i){

     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("\n");

 

   HC= (HuffmanCode)malloc((n+1)*sizeof(char *));

   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){

            if(HT[f].lchild == c)

               cd[ --start ] = '0';

            else

               cd[ --start ] = '1';

         }

        HC[i] = (char *) malloc((n-start) * sizeof(char));

        strcpy(HC[i],&cd[start]);

   }

  free(cd);

}

//选择两个权值最小的节点

void Select(HuffmanTree HT,int n,int&s1, int &s2){

  int i ,w;

   s1= s2 = 1;

   //选出第一个权值最小的节点

   w=100000;

  for( i=1 ;i<=n;i++){

    if(HT[i].parent == 0 && w > HT[i].weight){

       w  = HT[i].weight;

       s1 = i ;

    }

   }

    //将权值初始值w重置最大,选出第二个权值最小的节点

   w=100000;

  for( i=1 ;i<=n;i++){

     if(HT[i].parent == 0  && w>HT[i].weight && i != s1 ){

       w  = HT[i].weight;

       s2 = i ;

    }

   }

}

 

//统计字符串str中各字符的个数

void Huffmans (int w[],char *str,int&n,char *a){

   int i,j;

   n=0;

   //将个数初始化为0

   for(j=0; j<60;j++){

       w[j] = 0;

    }

   //遍历

   for(i=0; str[i]!='\0'; i++){

       if(str[i]  ==' '){

            w[52]++;

        }else{

            w[str[i]-65]++;

       }

    }

   for(i=0;i<60;i++){

       if(w[i]!=0) n++;

    }

   j=0;

   for(i=0;i<60;i++){

      if(w[i] != 0){

          if(i == 52)

          {

               a[j] = ' ';

          }

          else

          {

               a[j] = i+65;

          }

          j++;

      }

    }

   printf("\n");

}

//从1.txt中读取字符串

 voidinputfile(char *str){

   int index  = 0;

   char ch;

   FILE *fp;

   fp = fopen("1.txt","r");

   while((ch = fgetc(fp)) != EOF){

           str[index++] = ch;

    }

   str[index] = '\0';

   fclose(fp);

 }

//将编码后的字符写入到文件中

 voidoutputfile(HuffmanCode HC,int n,char *a){

   FILE *fp;

   int i,j;

   fp = fopen("1.txt", "a+");

   if (fp==0) {

       printf("不能打开文件\n"); return ;

    }

   fseek(fp, 0, SEEK_END);        //设置文件指针

   for(i=1 ; i<=n;i++){

       fprintf(fp,"\n");

       fprintf(fp,"%c的编码: ",a[i-1]);

       for(j=0; j<n; j++){

           if(HC[i][j] == '0' || HC[i][j] == '1'){

                fprintf(fp,"%c ",HC[i][j]);

           }

       }

    }

   fclose(fp);

 }

 

     
     
    
    
   
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值