霍夫曼编码!请教高手!加分100哈!

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了霍夫曼编码!请教高手!加分100哈!相关的知识,希望对你有一定的参考价值。

根据列句中字符(字符!空格和 句号要算哈)出现的概率!进行!霍夫曼编码!!! 详细点!!
A good beginning is half done.
我要的是 答案!!!!!!!!!!!

参考技术A 二.霍夫曼编码

霍夫曼(Huffman)编码属于码词长度可变的编码类,是霍夫曼在1952年提出的一种编码方法,即从下到上的编码方法。同其他码词长度可变的编码一样,可区别的不同码词的生成是基于不同符号出现的不同概率。生成霍夫曼编码算法基于一种称为“编码树”(coding tree)的技术。算法步骤如下:

(1)初始化,根据符号概率的大小按由大到小顺序对符号进行排序。

(2)把概率最小的两个符号组成一个新符号(节点),即新符号的概率等于这两个符号概率之和。

(3)重复第2步,直到形成一个符号为止(树),其概率最后等于1。

(4)从编码树的根开始回溯到原始的符号,并将每一下分枝赋值为1,上分枝赋值为0。

以下这个简单例子说明了这一过程。

1).字母A,B,C,D,E已被编码,相应的出现概率如下:

p(A)=0.16, p(B)=0.51, p(C)=0.09, p(D)=0.13, p(E)=0.11

2).C和E概率最小,被排在第一棵二叉树中作为树叶。它们的根节点CE的组合概率为0.20。从CE到C的一边被标记为1,从CE到E的一边被标记为0。这种标记是强制性的。所以,不同的哈夫曼编码可能由相同的数据产生。

3).各节点相应的概率如下:

p(A)=0.16, p(B)=0.51, p(CE)=0.20, p(D)=0.13

D和A两个节点的概率最小。这两个节点作为叶子组合成一棵新的二叉树。根节点AD的组合概率为0.29。由AD到A的一边标记为1,由AD到D的一边标记为0。

如果不同的二叉树的根节点有相同的概率,那么具有从根到节点最短的最大路径的二叉树应先生成。这样能保持编码的长度基本稳定。

4).剩下节点的概率如下:

p(AD)=0.29, p(B)=0.51, p(CE)=0.20

AD和CE两节点的概率最小。它们生成一棵二叉树。其根节点ADCE的组合概率为0.49。由ADCE到AD一边标记为0,由ADCE到CE的一边标记为1。

5).剩下两个节点相应的概率如下:

p(ADCE)=0.49, p(B)=0.51

它们生成最后一棵根节点为ADCEB的二叉树。由ADCEB到B的一边记为1,由ADCEB到ADCE的一边记为0。

6).图03-02-2为霍夫曼编码。编码结果被存放在一个表中:

w(A)=001, w(B)=1, w(C)=011, w(D)=000, w(E)=010

图03-02-2 霍夫曼编码例

霍夫曼编码器的编码过程可用例子演示和解释。

下面是另一个霍夫曼编码例子。假定要编码的文本是:

"EXAMPLE OF HUFFMAN CODE"

首先,计算文本中符号出现的概率(表03-02-2)。

表03-02-2 符号在文本中出现的概率

符号
概率

E
2/25

X
1/25

A
2/25

M
2/25

P
1/25

L
1/25

O
2/25

F
2/25

H
1/25

U
1/25

C
1/25

D
1/25

I
1/25

N
2/25

G
1/25

空格
3/25

最后得到图03-02-3所示的编码树。

图03-02-3 霍夫曼编码树

在霍夫曼编码理论的基础上发展了一些改进的编码算法。其中一种称为自适应霍夫曼编码(Adaptive Huffman code)。这种方案能够根据符号概率的变化动态地改变码词,产生的代码比原始霍夫曼编码更有效。另一种称为扩展的霍夫曼编码(Extended Huffman code)允许编码符号组而不是单个符号。

同香农-范诺编码一样,霍夫曼码的码长虽然是可变的,但却不需要另外附加同步代码。这是因为这两种方法都自含同步码,在编码之后的码串中都不需要另外添加标记符号,即在译码时分割符号的特殊代码。当然,霍夫曼编码方法的编码效率比香农-范诺编码效率高一些。

采用霍夫曼编码时有两个问题值得注意:①霍夫曼码没有错误保护功能,在译码时,如果码串中没有错误,那么就能一个接一个地正确译出代码。但如果码串中有错误,那怕仅仅是1位出现错误,也会引起一连串的错误,这种现象称为错误传播(error propagation)。计算机对这种错误也无能为力,说不出错在哪里,更谈不上去纠正它。②霍夫曼码是可变长度码,因此很难随意查找或调用压缩文件中间的内容,然后再译码,这就需要在存储代码之前加以考虑。尽管如此,霍夫曼码还是得到广泛应用。
http://210.41.4.20/course/58/58/MMT/Mmt03_02_2.htm

参考资料:http://210.41.4.20/course/58/58/MMT/Mmt03_02_2.htm

数据结构--哈弗曼编码器

哈夫曼编码


本人比较懒….关于哈夫曼树知识点的介绍就不在博客上说了, 请同学们自行查阅相关资料, 直接上代码, 简单 ,粗暴.
如果有哪里没看明白或者是对程序有更好的见解, 请评论在博文的下方, 或者私信我, 我看到后会第一时间回复, 希望大家踊跃发言


语言: C

知识点: 哈夫曼编码


问题描述: 问题描述:设计一个赫夫曼编码译码系统,对某个英文文本文件(.txt)中的字符进行哈夫曼编码,并将该txt文件生成编码文件(.cod);反过来还可将一个编码文件(.cod)还原为一个文本文件(.txt)。


功能及界面要求

本题可采用console控制台或可视化界面,console控制台参考界面如下
                   哈夫曼编码译码器                           
*       1、选择需要进行编码的文件                                   
*       2、建立哈夫曼树                                             
*       3、建立密码本并对文件编码                                   
*       4、选择需要进行解码的文件并解码                             
*       5、按位压缩方式对文件进行压缩                               

功能说明

①“选择需要进行编码的文件”:选择该选项后,提示用户输入(或选择)要进行编码(加密)的文件(包括路径和文件名)。
②“建立哈夫曼树”: 选择该选项后,程序根据1中确定的文件建立哈夫曼树。
③“建立密码本并对文件编码”: 选择该选项后,程序根据2中建立好的哈夫曼树为1中出现的每个字符建立编码,并对文件进行编码,在进行编码前提示用户将编码文件存放在哪个文件(文件扩展名为cod)中。
④“选择需要进行解码的文件并解码”: 选择该选项后,提示用户输入(或选择)需要进行解码(译码)的文件(文件扩展名为cod),并输入(或选择)将解码(译码)后的文件存放到哪个文件(文件扩展名为txt),程序将cod文件根据3建立的密码本进行解码,解码到txt文件中。
⑤“按位压缩方式对文件进行压缩”:对cod文件进行压缩,显示压缩比(即压缩后的编码文件字节数/编码前的原txt文件字节数),并能对压缩后的cod文件进行解码。


存储要求:

 哈夫曼树采用数组存储
 密码本在内存中采用数组存储,也可根据用户选择将密码本存到文件中。
 编码文件和译码文件都采用文本文件存储。


算法及技术指导:

①为实现功能2,首先用对原txt文件进行扫描,得到每个字符(包括空格、标点符号和回车换行)出现的次数,并根据教材提供的算法得到哈夫曼树。
②为实现功能3,首先根据哈夫曼树及教材提供的算法得到每个出现字符的哈夫曼编码( 即建立密码本),并对原txt文件重新进行扫描,扫描到某个字符时在密码本中找到该字符的哈夫曼编码,写入到编码文件中。
③为实现功能4,要扫描编码文件,扫描(读)到‘0’或‘1’时,根据哈夫曼树进行相应的处理,直到扫描(读)到某个‘0’或‘1’后,哈夫曼树已经到达某个叶子,将该叶子对应的字符写入到解码文件中。
④为实现功能5,对编码后的cod文件进行处理,将每8个(‘0’或‘1’)字符串转化为相应的整数(用1个字节存储)并写入压缩文件中,注意对最后一个01串(长度<=8)的处理。


代码如下

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>

using namespace std;

char filenamemi[100];
char filefile[100];
char filebian[100];

typedef struct

    int weight;
    char flag;
    int parent, lchild, rchild;
 HTNode, *HuffmanTree;
typedef struct ASCII

    char flag;
    int c;
    struct ASCII *next;
 ASCII, *LinkList;
typedef struct txt

    char flag;
    char hafuman[5000];
 txtNode;

LinkList L;
typedef char **HuffmanCode;

bool InitList(LinkList &L)//初始化链表

    L = new ASCII;
    L->c  = 1;
    L->next = NULL;
    return true;


void Show(LinkList L)//显示链表

    LinkList p;
    p = L->next;
    while(p)
    
        printf("  %c, %d\\n", p->flag, p->c);
        p = p->next;
    
    cout<<endl;


int Choice() //选择文件以及创建权重值

    FILE *fp;
    char a;
    int num = 0, key = 0;
    int instance = 0;
    LinkList  p, s, m;
    InitList(L);
    s = L;
    m = L;
    getchar();
    //char filefile[100] ;
    while(!key)
    
        printf("请输入你要打开的文件名及路径,如c:\\\\users\\\\lenovo\\\\desktop\\\\7\\\\1.txt\\n");
        gets(filefile);
        if ((fp=fopen(filefile,"r"))==NULL)
        
            printf("打开文件%s出现错误\\n",filefile);
            key = 0;
            return 0;
        
        key = 1;
    

    while((a = fgetc(fp)) != EOF)
    
        s = L->next;
        printf("%c ", a);
        while(s)
        
            if(s->flag == a)//如果在文本中出现了, 当前字符, 那么当前字符的权重值++
            
                s->c++;
                instance = 1;
                break;
            
            s = s->next;
        
        if(instance == 0)//如果当前文本没有改字符, 那么, 创建该字符,插入到文本当中
        
            p = new ASCII;
            p->flag = a;
            p->c = 1;
            m->next = p;
            p->next = NULL;
            m = p;
            num++;//文本中多少结点
        
        instance = 0;
    
    cout<<endl;
    Show(L);
    //fseek(fp,0,SEEK_SET);
    fclose(fp);
    return num;


void Select(HuffmanTree &HT, int num, int *s1, int *s2) //寻找两个最小的且双亲为0的最小节点

    int i, sec = 0, fir = 0;//a是次小, b是最小
    int second = -1, first = -1;
    HTNode L1, L2;//L1次小, L2最小
    for(i = num; i >= 1; i--)//选择两个双亲部不为0的结点
    
        if(HT[i].parent == 0 && second == -1) second = i;
        else if(HT[i].parent == 0 && first == -1) first = i;

        if(first!=-1 && second!=-1) break;
    
    //cout<<second<<" "<<first<<endl;
    if(HT[second].weight > HT[first].weight)
    
        L1 = HT[second];
        L2 = HT[first];
        sec = second;
        fir = first;
    
    else
    
        L1 = HT[first];
        L2 = HT[second];
        sec = first;
        fir = second;
    

    for(i = num; i >= 1; i--)//从剩下的节点中找到两个最小的节点
    
        if( (HT[i].weight < L2.weight) &&(HT[i].parent == 0) && i!=second && i!=first)
        
            L1 = L2;
            L2 = HT[i];
            sec = fir;
            fir = i;
        
        else if( (HT[i].weight < L1.weight) && (HT[i].parent == 0) && i!=second && i!=first)
        
            L1 = HT[i];
            sec = i;
        
    
    *s1 = fir;
    *s2 = sec;


bool CreatHuffmanaTree(HuffmanTree &HT, int num) //创建哈夫曼树

    int m, i;
    LinkList p;
    p = L->next;
    if(num <= 1) return false;
    m = 2*num-1;
    HT = new HTNode[m+1];
    for(i = 1; i <= m; i++)
    
        HT[i].parent = 0;
        HT[i].lchild = 0;
        HT[i].rchild = 0;
    
    for(i = 1; i <= num; i++)
    
        HT[i].weight = p->c;
        HT[i].flag = p->flag;
        p = p->next;
    

    int s1=0, s2=0;
    for(i = num+1; i <= m; i++)
    
        Select(HT, i-1, &s1, &s2);
        //cout<<s1<<" "<<s2<<endl;
        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;
    
    return true;


bool CreatHuffmanaCode(HuffmanTree HT, int num) //创建哈夫曼编码

    char  *cd;
    int i, c, f, start, key = 0;
    FILE *fp;
    char flag;
    getchar();
    while(!key)
    
        printf("请输入你要保存密码本的文件名及路径,如c:\\\\users\\\\lenovo\\\\desktop\\\\7\\\\密码本.txt\\n");
        gets(filenamemi);
        if ((fp=fopen(filenamemi,"w"))==NULL)
        
            printf("保存文件%s出现错误, 请重新输入\\n",filenamemi);
            key = 0;
        
        key = 1;
    
    cd = new char[num];
    cd[num-1] = '\\0';
    for(i = 1; i <= num; i++)
    
        start = num-1;
        c = i;
        f = HT[i].parent;
        flag = HT[i].flag;
        while(f != 0)
        
            --start;
            if(HT[f].lchild == c) cd[start] = '0';
            else cd[start] = '1';
            c = f;
            f = HT[f].parent;
        

        printf("%c %s\\n", flag, &cd[start]);
        fprintf(fp,"%c %s\\n", flag, &cd[start]);
    
    delete cd;
    fclose(fp);


bool CreatTxtCode(int num)//创建文本编码

    FILE *fp, *fp1, *fp2;
    int key = 0;
    //char filename[100];
    txtNode txt[257];
    char a;
    getchar();
    while(!key)
    
        printf("请输入你要保存编码的文件名及路径,如c:\\\\users\\\\lenovo\\\\desktop\\\\7\\\\1.cod\\n");
        gets(filebian);
        if ((fp=fopen(filebian,"w"))==NULL)
        
            printf("保存文件%s出现错误, 请重新输入\\n",filebian);
            key = 0;
        
        key = 1;
    
    int i = 0, nu = 1, j;
    fp1 = fopen(filenamemi,"r");
    fp2 = fopen(filefile,"r");

    char interim[1000];
    fgets(interim, 100, fp1);
    while(!feof(fp1))
    
        txt[nu-1].flag = interim[0];
        i = strlen(interim);
        for(j = 2; j < i-1; j++)
        
            txt[nu-1].hafuman[j-2] = interim[j];
        
        fgets(interim, 100, fp1);
        nu++;
    
    for(i = 0; i <= nu; i++)
    
        cout<<txt[i].flag<<"  "<<txt[i].hafuman<<endl;
    
    while((a = fgetc(fp2)) != EOF)
    
        for(i = 0; i <= nu; i++)
        
            if(a == txt[i].flag)
            
                fprintf(fp,"%s",txt[i].hafuman);
            
        
    
    fclose(fp);
    fclose(fp1);
    fclose(fp2);
    return true;


bool ReductionTxt(HuffmanTree HT, int num)//创建文本节点

    FILE *fp, *fp1;//fp----编码文件    fp1------还原之后的文件
    int key = 0;
    char filename[100],  filename1[100];
    char a;
    getchar();
    if ((fp=fopen(filebian,"r"))==NULL)
    
        printf("打开文件%s出现错误\\n",filebian);
        key = 0;
        return false;
    
    while(!key)
    
        printf("请输入你要保存的文件名及路径,如c:\\\\users\\\\lenovo\\\\desktop\\\\7\\\\2.txt\\n");
        gets(filename1);
        if ((fp1=fopen(filename1,"w"))==NULL)
        
            printf("打开文件%s出现错误\\n",filename1);
            key = 0;
            return false;
        
        key = 1;
    

    int kk = 2*num-1;
    while((a = fgetc(fp)) != EOF)
    
        if(a == '0')
        
            kk = HT[kk].lchild;
        
        else
        
            kk = HT[kk].rchild;
        

        if( (HT[kk].lchild == 0)  && (HT[kk].rchild == 0) )
        
            fprintf(fp1,"%c", HT[kk].flag);
            kk = 2*num-1;
        
    
    fclose(fp);
    fclose(fp1);
    return true;


void zip()//压缩文件

    FILE *fp, *fp1;//fp----编码文件    fp1------压缩文件
    int key = 0, in, i;
    char filename[100],  filename1[100];
    char a;
    int twopower[11] = 1,2,4,8,16,32,64,128,256,512,1024;
    getchar();
    if ((fp=fopen(filebian,"r"))==NULL)
    
        printf("打开文件%s出现错误\\n",filebian);
        key = 0;
        return;
    
    key = 0;
    while(!key)
    
        printf("请输入保存的文件名及路径,如C:\\\\users\\\\lenovo\\\\desktop\\\\7\\\\2.cod\\n");
        gets(filename1);
        if ((fp1=fopen(filename1,"w"))==NULL)
        
            printf("打开文件%s出现错误\\n",filename1);
            key = 0;
            return ;
        
        key = 1;
    
    //fp1=fopen("C:\\\\users\\\\lenovo\\\\desktop\\\\7\\\\2.cod","w");
    in = 0;
    int sum = 0, fla = 2;
    a = fgetc(fp);
    while(!feof(fp))
    
        sum = sum + int(a-'0')*twopower[7-in];
        //cout<<int(a-'0')<<" "<<twopower[in]<<" "<<sum<<endl;
        in++;
        a = fgetc(fp);
        if(in == 8 || feof(fp))
        
            in = 0;
            fprintf(fp1, "%d ", sum);
            sum = 0;
        
    
    fclose(fp);
    fclose(fp1);



int main()

    int num;
    HuffmanTree L;
start:
    printf("******************************************************************\\n\\n");
    printf("哈夫曼编码译码器\\n\\n");
    printf("*\\t1、选择需要进行编码的文件\\t\\t*\\n\\n");
    printf("*\\t2、建立哈夫曼树\\t\\t\\t\\t*\\n\\n");
    printf("*\\t3、建立密码本并对文件编码\\t\\t*\\n\\n");
    printf("*\\t4、选择需要进行解码的文件并解码\\t\\t*\\n\\n");
    printf("*\\t5、按位压缩方式对文件进行压缩\\t\\t*\\n\\n\\n");
    printf("******************************************************************\\n\\n");
    int option = 0;
    cin>>option;
    while(1)
    
        switch(option)
        
        case 1:
            num = Choice();
            break;
        case 2:
            if(CreatHuffmanaTree(L, num))cout<<"成功"<<endl;
            break;
        case 3:
            CreatHuffmanaCode(L, num);
            if(CreatTxtCode(num)) cout<<"成功"<<endl;
            break;
        case 4:
            if(ReductionTxt(L, num)) cout<<"成功"<<endl;
            break;
        case 5:
            zip();
            break;
        
        goto start;
    


    //cout<<endl;
    //cout<<endl;

    //releasezip();
    return 0;

以上是关于霍夫曼编码!请教高手!加分100哈!的主要内容,如果未能解决你的问题,请参考以下文章

哈弗曼树与哈夫曼编码

哈夫曼编码问题,高手帮我

哈夫曼编码记录

数据结构--哈弗曼编码器

哈夫曼树及其编码

(王道408考研数据结构)第五章树-第四节3:哈夫曼树基本概念构造和哈夫曼编码