哈夫曼编码和译码

title: 哈夫曼编码和译码
date: 2018-11-21 12:01:27
tags: [数据结构]
categories: 数据结构

实验二 哈夫曼编码和译码

实验目的

1、熟悉二叉树的顺序存储结构;

2、熟悉二叉树的顺序存储结构和具体实现;

3、熟悉哈夫曼编码和译码,及其在顺序存储结构下的实现

实验要求:

1、根据输入构造一棵哈夫曼树,要求该哈夫曼树的左子树小于等于右子树;

2、根据构造的哈夫曼树给出对应的编码;左子树的编码为0,右子树的编码为1;

3、输出各个字符对应的编码与平均编码长度;

4、根据输入的编码,结合构造的哈夫曼树给出对应的译码

5、对带有不同权值的字符进行编码;使用自己实现的编码表对输入的‘0’‘1’代码进行译码

数据输入输出要求

输入示例

5

A 8

B 20

C 30

D 15

E 27

0101101110#

(说明:第一个数据5表示共有5个字符要编码,后面的“A 8”表示A的权为8,字符个数不超过20个;数据0101101110#是要解码的数据,最后以#结束)

输出示例

编码为: A 010

B 00

C 11

D 011

E 10

平均编码长度为:2.23

对应的译码为:ACDE

代码

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <iostream>
const int INF=0x3f3f3f3f;
using namespace std;
typedef struct
{
    char ch;                     //字母与编码
    int weight;                  //权重
    int parent, lchild, rchild;   //父亲与左右孩子
}HTNode, *HuffmanTree;
typedef char **HuffmanCode;
int Floor[25];
​
//以下为函数原型声明
void   CreateHuffmanTree(HuffmanTree &HT, int w[], char ch[], int n);//构造HuffmanTree
void   Select(HuffmanTree HT, int  n, int &s1, int &s2); //选择两个权重最小的无父亲的结点
void   HTCoding(HuffmanTree HT, HuffmanCode &HC, int n); //利用HuffmanTree对字符编码
void   PrintCode(HuffmanCode HC, int n, char ch[]);//输出编码
double AverageLenght(HuffmanTree HT, HuffmanCode HC, int n); //求平均编码长度
void   DeCode(HuffmanTree HT, int n);//解码
​
int main()
{
    int n;
    int i;
    char arrch[20];
    int arrweight[20];
    double avlength;
    char ch;
    HuffmanTree HT; //HT是一个指针变量,用于指向HuffmanTree
    HuffmanCode HC; //HC是一个指针变量,用于存放对应字符的编码
    scanf("%d",&n);//输入字符个数
    while((ch=getchar())!='\n');
    if(n>20||n<2)   exit(0); //输入的字符数超出要求范围退出;
    for(i=0;i<n;i++)  //输入字符和对应的权重
    {
        scanf("%c",&arrch[i]);
        scanf("%d",&arrweight[i]);
        while((ch=getchar())!='\n');
    }
    CreateHuffmanTree(HT,arrweight,arrch,n);//构造HuffmanTree
    HTCoding(HT,HC,n);//利用HuffmanTree对字符编码
    PrintCode(HC,n,arrch);  //输出编码
    avlength=AverageLenght(HT,HC,n);//求平均编码长度
    printf("平均编码长度为:%.2f\n",avlength);
    DeCode(HT,n);//解码
    for(i=0;i<n;i++)
        free(HC[i]);
    free(HC);
    free(HT);
}//end_main
​
void CreateHuffmanTree(HuffmanTree &HT,int w[],char ch[],int n)
{
    // w存放n个字符的权值(均>0),构造哈夫曼树HT,
    int i, m,s1, s2;
    m = 2 * n - 1;
    HT = (HuffmanTree)malloc((m+1) * sizeof(HTNode));  // 0号单元不用
    //设有一组权值存放于数组w[]中,对应的字符在数组ch[]中
    for (i=1; i<=n; i++)
    {
        HT[i].weight=w[i-1];
        HT[i].parent=0;
        HT[i].lchild=0;
        HT[i].rchild=0;
       HT[i].ch =ch[i-1];
     }
     //数组HT后n-1个元素先清空
    for (i=n+1; i<=m; i++)
    {
        HT[i].weight=0;
        HT[i].parent=0;
        HT[i].lchild=0;
        HT[i].rchild=0;
        HT[i].ch='\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;
    }
}
​
void Select(HuffmanTree HT, int  n, int &s1, int &s2)
{      //补充完整
    int t1=INF;
    int t2=INF;
    for(int i=1;i<=n;i++)
    {
        if(HT[i].parent==0)//未被选过
        {
            if(HT[i].weight<t1)//选为s1
                {
                    s1=i;
                    t1=HT[s1].weight;
                }
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(HT[i].parent==0&&i!=s1)//未被选过且没被选为s1
        {
            if(HT[i].weight<t2)//选为s2
                {
                    s2=i;
                    t2=HT[s2].weight;
                }
        }
    }
}//end_Select
​
void HTCoding(HuffmanTree HT,HuffmanCode &HC,int n)
{
        // 从叶子到根逆向求每个字符的哈夫曼编码
    int i,j,k, start;
    int f;
    int c;
    char * cd;
    HC=(HuffmanCode)malloc((n)*sizeof(char *));
    cd=(char *)malloc(n*sizeof(char));    // 分配求编码的工作空间
    cd[n-1]='\0';                         // 编码结束符。
    for (i=1; i<=n; ++i)
    {
        Floor[i]=0;              // 逐个字符求哈夫曼编码
        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';
                //cout<<"0";
                }
​
            else
                {cd[--start] = '1';
                //cout<<"1";
                }
            Floor[i]++;
        }
        HC[i-1]=(char *)malloc((n-start)*sizeof(char));
        for(j=start,k=0;j<n;j++,k++)// 从cd复制编码(串)到HC
            {
                HC[i-1][k]=cd[j];
            //cout<<cd[j];
            }
    }
    //cout<<HC[4];
    free(cd);   // 释放工作空间
}//end_HTCoding
​
void PrintCode(HuffmanCode HC, int n, char ch[]) //输出编码
{ //补充完整
    for(int i=0;i<n;i++)
    {
        //printf("%c %s\n",ch[i-1],&HC[i-1]);
        if(i==0)
        {
            printf("编码为:");
            printf("%8c  %s\n",ch[i],HC[i]);
        }
        else
            printf("%16c  %s\n",ch[i],HC[i]);
    }
}//end_PrintCode
​
double AverageLenght(HuffmanTree HT, HuffmanCode HC, int n)//求平均编码长度
{//补充完整
    double sum=0;
    for(int i=1;i<=n;i++)
    {
        sum+=Floor[i]*HT[i].weight/100.0;
        //cout<<Floor[i]<<endl;
    }
    return sum;
}//end_AverageLenght
​
void DeCode(HuffmanTree HT,int n)//解码
{
      int  i;
      char endflag='#';
      char ch;
      i=2*n-1;                        /*从根结点开始往下搜索*/
      scanf("%c",&ch);    /*读入一个二进制码*/
      printf("对应的译码为:");
      while (ch!=endflag)
      {
            if (ch=='0')
                i=HT[i].lchild;
            else  i=HT[i].rchild;
​
            if(HT[i].lchild==0)       /*tree[i] 是叶子结点*/
            {
                printf("%c",HT[i].ch);
                i=2*n-1;
            }
            scanf("%c",&ch);
        }
        if ((HT[i].lchild!=0) && (i!=2*n-1))  //电文读完但没到叶子结点
            printf("\n未能完全解码\n");
        printf("\n");
}//end_DeCode

注意

统计层数用了全局变量数组,不是很好,应该以strlen(HC[I])代替。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值