求高手写个关于哈夫曼编码的算法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求高手写个关于哈夫曼编码的算法相关的知识,希望对你有一定的参考价值。

根据哈夫曼编码思想,设计一个加/解密程序,输入不少于100 个字符的短文(明文)进行测试,并输出明文,密码表,密文,同时用文件保存之。

恩,楼主这个题目相当复杂啊
首先读文件,按字符读。一个一个读,统计所有出现字符的频数。
记录到一个链表里吧
第二步,建树。霍夫曼树……复杂程度可想而知。
Huffman 算法
思想: 权大的外结点靠近根, 权小的远离根。
算法: 从m个权值中找出两个最小值W1,W2构成
w
w1 w2 W=W1+W2表通过该结点的频度。
依次往上找……
估计你的100个字符的短文,出现的字符数量估计平均有20个左右,建的树的高度就12就算低的。
3 按结点到跟的距离编码,从左到右编码为0 1 0 1依次进行……
生成霍夫曼编码
把每个字幕的二进制编码记录,打出,这就是密码表
然后对原来的文件进行打印,碰到相应的字母打印出相应的密码(二进制啊,汗……)
估计只有拿到密码才能看明白那一串的01!!
如果某一电文出现的字符为D=M,S,T,A,Q, K , 每个字符出现的频率为W=10,29,4,8,15,7,
则用改算法生成的密码为:
S:0 A:100 M:101 Q:111
T:1100 K:1101
100 1100 101 0 111 0 1101 0 0 密文的含义是:
A T M S Q S K S S
参考技术A 楼主真幸运,我这儿有现成的C语言代码:
#include <stdio.h>
#define N 7 /*叶子数目,需要时更改此值即可*/
#define M 2*N-1 /*节点总数*/

typedef struct

char bits[N];/*编码存储,位串*/
int start; /*编码在位串中的位置*/
codetype;

typedef struct

float weight;
int lchild,rchild,parent;
hufmtree;

void HUFFMAN(tree1)
hufmtree tree1[];

int i,j,p1,p2;
float small1,small2,f;
hufmtree *tree;
tree=tree1;
for(i=0;i<M;i++) /*初始化*/

tree[i].parent=0;
tree[i].lchild=0;
tree[i].rchild=0;
tree[i].weight=0.0;

printf("please input a possible data weight:\n"); /*输入信源数据*/
for(i=0;i<N;i++) /*输入前n个节点的权值*/

scanf("%f",&f);
tree[i].weight=f;

for(i=N;i<M;i++) /* 进行n-1次合并,产生n-1个新的节点*/

p1=0,p2=0;
small1=1;small2=1;
for(j=0;j<=i-1;j++) /*从所有的节点中,选出两个权值最小的根节点*/
if(tree[j].parent==0) /*parent值为0,则显示根节点,否则便是非根节点*/
if(tree[j].weight<small1)

small2=small1; /*改变最小权,次小权及对应的位置*/
small1=tree[j].weight;
p2=p1; /*p1、p2记住这两个根节点在向量tree中的下标*/
p1=j;

else if(tree[j].weight<small2)

small2=tree[j].weight;/*次小权及位置*/
p2=j;

tree[p1].parent=i+1; /*节点分量与下标之间差值为1*/
tree[p2].parent=i+1; /*节点的标号i+1*/
tree[i].lchild=p1+1; /*最小值根节点是新节点的左孩子,分量标号是其下标加1*/
tree[i].rchild=p2+1; /*次小权根节点是新节点的右孩子*/
tree[i].weight=tree[p1].weight+tree[p2].weight;

/*HUFFMANTREE()*/

void HUFFMANCODE(code1,tree1) /*根据哈夫曼树求出哈夫曼编码*/
codetype code1[]; /*求出的哈夫曼编码所在*/
hufmtree tree1[];/*已知的哈夫曼树*/

int i,j,c,p;
codetype cd;/*缓冲变量*/
codetype *code;
hufmtree *tree;
code=code1;
tree=tree1;
for(i=0;i<N;i++)

cd.start=N;
c=i+1; /*从叶节点出发向上回溯*/
p=tree[i].parent;/*tree[p-1]是tree[i]的双亲*/
while(p!=0)

cd.start--;
if(tree[p-1].lchild==c)
cd.bits[cd.start]='0'; /*tree[i]是左子树。生成代码'0'*/
else
cd.bits[cd.start]='1'; /*否则tree[i]是右子树。生成代码'1'*/
c=p;
p=tree[p-1].parent;

code[i]=cd; /*第i+1个字符的编码存入code[i]*/

/*HUFFMANCODE*/

#include "stdio.h"
main()

int k1,k2;
hufmtree tree_fina[M];
hufmtree *p11=tree_fina;
codetype code_fina[N];
codetype *p21=code_fina;
HUFFMAN(p11); /*建立huffman树*/
HUFFMANCODE(p21,p11); /*haffman码*/
for(k1=0;k1<N;k1++) /*输出编码*/

printf("number %d haffmancode: ",k1+1);
for(k2=code_fina[k1].start;k2<N;k2++)
printf(" %c",code_fina[k1].bits[k2]);
printf("\n");

(学习11)哈夫曼算法

问题描述:

已知字符出现的概率,如何设计为这些字符设计一定长度的位串,使得位串平均长度最短.

前缀码是指,对字符集进行编码时,要求字符集中任一字符的编码都不是其它字符的编码的前缀,而最优前缀码是指平均码长最小的前缀编码。

问题解析:

 

数据结构:二叉树

哈夫曼树的性质:

1:一共有2n-1个节点,其中n为叶子节点数,所以可以存在一个2n-1的一维数组中。

2:哈夫曼树没有度为1的节点

2:为求编码需要从叶子节点出发走到根节点,并且对于每个节点既要知道双亲节点,也要知道孩子节点

 

算法步骤:

 

1:从集合中选出权值最小的两个节点,然后形成一颗新的树,这颗树的根的权值为这两个节点的权值的和,然后将这颗树再放回集合。

 

2:重复步骤一,直至集合中只有一棵树。

 

3:根据这颗树,可对每个字符进行编码或解码,编码即从树根走到这个字符的路径所连成的二进制码,树中所有向左标记为0,向右标记为1.而解码就是读取该编码字符串,若该串与对应字符的前缀码对应,则输出字符,然后重新开始读取。

伪代码设计

技术图片
//
//  main.c
//  作业11
//
//  Created by yizhihenpidehou on 2020/5/12.
//  Copyright © 2020 yizhihenpidehou. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
    int weight;
    int lchild,rchild,parent;
}HTNode,*HuffmanTree;
typedef char **HuffmanCode;
HuffmanCode HC;
HuffmanTree HT;
int s1;
int s2;
void SelectMin(HuffmanTree tree,int n){ //找出权值最小的两棵树
    int minn=1;//存放临时最小值
    for(int i=1;i<=n;i++){
        if(tree[i].parent==0){//找出一个暂时的最小值
            minn=i;
            break;
        }
    }
    for(int i=1;i<=n;i++){
        if(tree[i].parent==0&&tree[i].weight<tree[minn].weight){//找出第一个最小值
            minn=i;
        }
    }
    s1=minn;
    for(int i=1;i<=n;i++){
        if(tree[i].parent==0&&i!=s1){//找出一个暂时的最小值
            minn=i;
            break;
        }
    }
    for(int i=1;i<=n;i++){
           if(tree[i].parent==0&&tree[i].weight<tree[minn].weight&&i!=s1){//找出第二个最小值
               minn=i;
           }
       }
       s2=minn;
  //  printf("s1:%d s2:%d
",s1,s2);
}
void Huffman(HuffmanTree tree,int *w,int n){//哈夫曼编码
    int m=2*n-1;//哈夫曼树的节点数
    tree=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//申请节点
    for(int i=1;i<=m;i++){//初始化树
        tree[i].lchild=0;
        tree[i].rchild=0;
        tree[i].parent=0;
        if(i<=n){//设置每个叶子节点的权值
           tree[i].weight=w[i];
        }
        else{
            tree[i].weight=0;
        }
    }
    for(int i=n+1;i<=m;i++){
        SelectMin(tree,i-1);
     //   printf("s1 %d s2 %d
",s1,s2);
        tree[s1].parent=i;//将s1的父亲设置为i
        tree[s2].parent=i;//将s2的父亲设置为i
        tree[i].lchild=s1;//将s1作为i的左孩子
        tree[i].rchild=s2;//将s2作为i的右孩子
        tree[i].weight=tree[s1].weight+tree[s2].weight;//i的权值为s1与s2的和
      //  printf("val s1:%d s2:%d
",tree[s1].weight,tree[s2].weight);
    //   printf("new NODE %d %d %d %d
",tree[i].parent,tree[i].lchild,tree[i].rchild,tree[i].weight);
    }
    //以上为建造一颗哈夫曼树,以下为求哈夫曼编码
    HC=(HuffmanCode)malloc((n+1)*(sizeof(char *)));//相当于申请一个二维数组,存放n个哈夫曼编码
    char *cd;
    cd=(char *)malloc(n*sizeof(char));//相当于申请一个一维数组,暂存哈夫曼编码
    cd[n-1]=;//编码结束符
    int start;
    for(int i=1;i<=n;i++){
        start=n-1;//初始点
        for(int j=i,f=tree[i].parent;f!=0;j=f,f=tree[f].parent){ //逆向求哈夫曼编码
            if(tree[f].lchild==j) cd[--start]=0; //向左为0
            else cd[--start]=1;//向右为1
        }
        HC[i]=(char *)malloc((n-start)*sizeof(char));
        strcpy(HC[i],&cd[start]);//将该字符的哈夫曼编码赋到HC中
        //printf("%c",cd[start]);
    }
    free(cd);
    
}
int main(int argc, const char * argv[]) {

    int n=10;
    int w[200]={0,30,40,20,10,5,15,10,45,20,60};//存放每个字符的权值
  //  int w1[200]={0,10,5,20};
    Huffman(HT, w, n);
  //  Huffmancode(HT,HC,n);
    for(int k=1;k<n;k++){//输出每个字符的哈夫曼编码
        printf("%s
",HC[k]);
    }
    printf("
");
    return 0;
}
View Code

源代码

技术图片
//
//  main.c
//  作业11
//
//  Created by yizhihenpidehou on 2020/5/12.
//  Copyright © 2020 yizhihenpidehou. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
    int weight;
    int lchild,rchild,parent;
}HTNode,*HuffmanTree;
typedef char **HuffmanCode;
HuffmanCode HC;
HuffmanTree HT;
int s1;
int s2;
void SelectMin(HuffmanTree tree,int n){ //找出权值最小的两棵树
    int minn=1;//存放临时最小值
    for(int i=1;i<=n;i++){
        if(tree[i].parent==0){//找出一个暂时的最小值
            minn=i;
            break;
        }
    }
    for(int i=1;i<=n;i++){
        if(tree[i].parent==0&&tree[i].weight<tree[minn].weight){//找出第一个最小值
            minn=i;
        }
    }
    s1=minn;
    for(int i=1;i<=n;i++){
        if(tree[i].parent==0&&i!=s1){//找出一个暂时的最小值
            minn=i;
            break;
        }
    }
    for(int i=1;i<=n;i++){
           if(tree[i].parent==0&&tree[i].weight<tree[minn].weight&&i!=s1){//找出第二个最小值
               minn=i;
           }
       }
       s2=minn;
  //  printf("s1:%d s2:%d
",s1,s2);
}
void Huffman(HuffmanTree tree,int *w,int n){//哈夫曼编码
    int m=2*n-1;//哈夫曼树的节点数
    tree=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//申请节点
    for(int i=1;i<=m;i++){//初始化树
        tree[i].lchild=0;
        tree[i].rchild=0;
        tree[i].parent=0;
        if(i<=n){//设置每个叶子节点的权值
           tree[i].weight=w[i];
        }
        else{
            tree[i].weight=0;
        }
    }
    for(int i=n+1;i<=m;i++){
        SelectMin(tree,i-1);
     //   printf("s1 %d s2 %d
",s1,s2);
        tree[s1].parent=i;//将s1的父亲设置为i
        tree[s2].parent=i;//将s2的父亲设置为i
        tree[i].lchild=s1;//将s1作为i的左孩子
        tree[i].rchild=s2;//将s2作为i的右孩子
        tree[i].weight=tree[s1].weight+tree[s2].weight;//i的权值为s1与s2的和
      //  printf("val s1:%d s2:%d
",tree[s1].weight,tree[s2].weight);
    //   printf("new NODE %d %d %d %d
",tree[i].parent,tree[i].lchild,tree[i].rchild,tree[i].weight);
    }
    //以上为建造一颗哈夫曼树,以下为求哈夫曼编码
    HC=(HuffmanCode)malloc((n+1)*(sizeof(char *)));//相当于申请一个二维数组,存放n个哈夫曼编码
    char *cd;
    cd=(char *)malloc(n*sizeof(char));//相当于申请一个一维数组,暂存哈夫曼编码
    cd[n-1]=;//编码结束符
    int start;
    for(int i=1;i<=n;i++){
        start=n-1;//初始点
        for(int j=i,f=tree[i].parent;f!=0;j=f,f=tree[f].parent){ //逆向求哈夫曼编码
            if(tree[f].lchild==j) cd[--start]=0; //向左为0
            else cd[--start]=1;//向右为1
        }
        HC[i]=(char *)malloc((n-start)*sizeof(char));
        strcpy(HC[i],&cd[start]);//将该字符的哈夫曼编码赋到HC中
        //printf("%c",cd[start]);
    }
    free(cd);
    
}
int main(int argc, const char * argv[]) {

    int n=10;
    int w[200]={0,30,40,20,10,5,15,10,45,20,60};//存放每个字符的权值
  //  int w1[200]={0,10,5,20};
    Huffman(HT, w, n);
  //  Huffmancode(HT,HC,n);
    for(int k=1;k<n;k++){//输出每个字符的哈夫曼编码
        printf("%s
",HC[k]);
    }
    printf("
");
    return 0;
}
View Code

时间复杂度 O(nlogn)

 

 

以上是关于求高手写个关于哈夫曼编码的算法的主要内容,如果未能解决你的问题,请参考以下文章

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

哈夫曼编码怎么求

算法与数据结构哈夫曼编码及应用

(学习11)哈夫曼算法

(学习11)哈夫曼算法

数据结构===哈夫曼编码实现/C或者C++