哈夫曼编码算法实现完整版

合集下载

哈夫曼编码过程

哈夫曼编码过程

哈夫曼编码过程介绍在计算机科学中,哈夫曼编码是一种使数据能够有效压缩和传输的算法。

它是一种无损压缩算法,能够将原始数据以最小的比特数表示。

哈夫曼编码由大卫·哈夫曼于1952年提出,从此成为数据压缩领域的重要算法之一。

原理哈夫曼编码的原理基于两个关键思想:频率越高的字符用更小的比特表示,频率越低的字符用更大的比特表示。

这样可以确保编码后的字符串具有唯一可识别性。

哈夫曼编码是通过构建哈夫曼树来实现的,具体步骤如下:1.统计每个字符在原始数据中出现的频率;2.根据字符频率构建哈夫曼树;3.根据哈夫曼树为每个字符生成对应的编码表;4.使用编码表将原始数据进行编码;5.将编码后的数据进行传输或存储。

构建哈夫曼树构建哈夫曼树的过程涉及到两个基本概念:结点和权值。

在哈夫曼树中,每个字符被表示为一个叶子结点,而非叶子结点的权值则代表了字符的频率。

构建哈夫曼树的步骤如下:1.将每个字符及其频率放入一个优先队列中,按照频率从小到大排列;2.从优先队列中取出两个权值最小的结点,将它们合并为一个新的结点,权值为两个结点的权值之和;3.将新结点插入优先队列中;4.重复步骤2和3,直到优先队列中只剩下一个结点,即为构建好的哈夫曼树。

生成编码表生成编码表的过程是通过遍历哈夫曼树来实现的。

步骤如下:1.从根结点开始,沿着左子树遍历到叶子结点,并在路径上添加比特’0’到编码表;2.回溯到上一个结点,遍历右子树,并在路径上添加比特’1’到编码表;3.重复步骤1和2,直到遍历完整个哈夫曼树。

编码过程有了编码表,就可以将原始数据进行编码。

步骤如下:1.从原始数据中取出一个字符;2.根据编码表找到该字符对应的比特序列,并将其添加到编码后的字符串中;3.重复步骤1和2,直到将所有字符编码为比特序列。

解码过程解码过程是将编码后的字符串重新还原为原始数据的过程。

解码过程依赖于编码表和哈夫曼树。

步骤如下:1.从编码后的字符串中取出比特序列;2.从根结点开始,按照比特序列的值向下遍历哈夫曼树;3.如果遇到叶子结点,就输出对应的字符,并返回到根结点;4.重复步骤2和3,直到将所有比特序列解码为字符。

哈夫曼编码的解码过程

哈夫曼编码的解码过程

哈夫曼编码的解码过程哈夫曼编码是一种被广泛应用于数据压缩领域的编码算法。

它通过构建一棵特殊的二叉树来实现对源数据的编码和解码。

在编码过程中,哈夫曼编码根据源数据的频率分配较短的编码给出现频率较高的字符,相反地,给出现频率较低的字符分配较长的编码,从而有效地减小编码后的数据长度。

而解码过程则是将编码后的数据转换为原始数据的过程。

一、哈夫曼编码的基本原理哈夫曼编码的基本原理是根据字符出现的频率来构建一棵哈夫曼树,以实现对字符的编码和解码。

具体步骤如下:1. 统计字符的频率:首先,需要对待编码的源数据进行扫描,并统计每个字符的出现频率。

通常可以使用哈希表等数据结构来记录字符及其对应的频率。

2. 构建哈夫曼树:根据字符的频率,构建一棵哈夫曼树。

构建哈夫曼树的算法可以采用贪心策略,即每次选择频率最小的两个节点合并,直到所有节点合并完毕,最终形成哈夫曼树。

3. 生成编码表:按照哈夫曼树的结构,为每个字符生成对应的编码。

从哈夫曼树的根节点开始,向左子树路径走一步表示编码位为0,向右子树路径走一步表示编码位为1,直到叶子节点,即可得到该字符的编码。

编码表可以使用哈希表等数据结构来存储字符和对应的编码。

4. 进行编码:将待编码的源数据字符根据编码表进行编码,生成对应的哈夫曼编码序列。

编码后的数据长度通常会显著减小,实现数据的压缩。

二、哈夫曼编码的解码过程哈夫曼编码的解码过程是将编码后的数据序列转换回原始数据的过程。

具体步骤如下:1. 读取编码序列:从编码后的数据中逐个读取编码位,直到读取到一个有效的编码。

2. 遍历哈夫曼树:从哈夫曼树的根节点开始,根据读取到的编码位,按照0表示左子树,1表示右子树的规则,不断遍历哈夫曼树,直到达到叶子节点。

3. 生成解码字符:在遍历过程中,若到达叶子节点,则表示找到了一个字符,将该字符输出。

然后重置遍历位置,继续读取编码序列,重复上述步骤,直至解码完成。

通过以上步骤,哈夫曼编码的解码过程完成,将编码后的数据序列转换回原始数据。

哈夫曼编码算法实现

哈夫曼编码算法实现

哈夫曼编码(Huffman Coding)是一种常见的数据压缩算法,它通过构建哈夫曼树(Huffman Tree)来实现。

以下是一个简单的哈夫曼编码算法的实现示例,使用Python 语言:pythonCopy codeimport heapqfrom collections import defaultdictclass HuffmanNode:def __init__(self, char, frequency):self.char = charself.frequency = frequencyself.left = Noneself.right = Nonedef __lt__(self, other):return self.frequency < other.frequencydef build_huffman_tree(data):frequency = defaultdict(int)for char in data:frequency[char] += 1priority_queue = [HuffmanNode(char, freq) for char, freq in frequency.items()]heapq.heapify(priority_queue)while len(priority_queue) > 1:node1 = heapq.heappop(priority_queue)node2 = heapq.heappop(priority_queue)merged_node = HuffmanNode(None, node1.frequency + node2.frequency)merged_node.left = node1merged_node.right = node2heapq.heappush(priority_queue, merged_node)return priority_queue[0]def build_huffman_codes(root, current_code="", codes={}):if root:if root.char is not None:codes[root.char] = current_codebuild_huffman_codes(root.left, current_code + "0", codes)build_huffman_codes(root.right, current_code + "1", codes)return codesdef huffman_encoding(data):if not data:return None, Noneroot = build_huffman_tree(data)codes = build_huffman_codes(root)encoded_data = "".join([codes[char] for char in data])return encoded_data, rootdef huffman_decoding(encoded_data, root):if not encoded_data or not root:return Nonecurrent_node = rootdecoded_data = ""for bit in encoded_data:if bit == "0":current_node = current_node.leftelse:current_node = current_node.rightif current_node.char is not None:decoded_data += current_node.charcurrent_node = rootreturn decoded_data# 示例data = "abracadabra"encoded_data, tree_root = huffman_encoding(data) decoded_data = huffman_decoding(encoded_data, tree_root)print("Original data:", data)print("Encoded data:", encoded_data)print("Decoded data:", decoded_data)。

数据结构 课程设计之哈夫曼编码

数据结构  课程设计之哈夫曼编码

(一) 哈夫曼树的设计思想对于一组具有确定权值的叶子结点可以构造出多个具有不同带权路径长度的二叉树,其中具有最小带权路径长度的二叉树称作哈夫曼树或者最优二叉树。

首先给定n 个权值创造n 个只含根结点的二叉树,得到一个二叉树林;再在这二叉树林里面找根结点的权值最小和次小的两棵树作成新的二叉树,其中新的二叉树的根结点的权值为摆布子根结点权值之和;最后在二叉树林中把组合过的二叉树删除,再重复第二步,直到最后就剩一颗二叉树的时候得到的这棵二叉树就是哈夫曼树。

(二)哈夫曼编码与解码的设计思想在数据通讯中,时常要将传送的文字转换为二进制字符0 和1 组成的二进制串,称这个过程为编码。

与子相对的是解码或者是译码,就是用与编码相同的方式将二进制串转换称编码前的文字的过程称作解码。

在这里是通过哈夫曼树实现编码与解码的,所以称作是哈夫曼编码与解码。

首先输入一个字符串,还有相应的在哈夫曼树里的权值,这样用哈夫曼树把字符串用二进制串代替它,这个过程要注意树和编码问题,其中树的问题在上面已经解决,主要看编码的问题,就是根据我们输入的字符串和权值建立相应的树模型,这一步完成那编码就已经完成为了,最后打印就行了;然后就是解码,完成编码相应的解码就相对简单了,就是先找到在编码的时候建的那个模型树,将编码中的二进制串再根据权值转换为相应的字符串,这样一步步解码就行了。

以上就是通过用哈夫曼树进行哈夫曼编码与解码如何实现的主要设计思想。

(一)哈夫曼树的流程图不 是图 1 哈夫曼树的流程图(二)编码与解码的流程图图 2 编码与解码的流程图图片说明: (左边)编码流程图, (右边)解码流程图。

开始输入字符串判断权值 建立路径有最小和次小 循环建立二叉树根据树对路径分左 0右 1写出对应结点的编码结束开始初始化哈夫曼链表二叉树林找最小和次小 的二叉树组合成新的二叉树 删除用过的二叉树是不是最后一 个二叉树是结束开始找到树的根结点 输入二进制串扫描根据树的路径打印对应字符继续扫描 是否结束是输出字符串结束否下面给出的是用中缀转后缀算法实现的程序的源代码:#include "stdio.h"#include "string.h"#define MAX 100struct HaffNode{int weight;int parent;char ch;int lchild;int rchild;}*myHaffTree;struct Coding{char bit[MAX];char ch;int weight;}*myHaffCode;void Haffman(int n){int i,j,x1,x2,s1,s2;for (i=n+1;i<=2*n-1;i++) {s1=s2=10000;x1=x2=0;for (j=1;j<=i-1;j++)/*定义常量*//*权值*//*双亲结点下标*//*构造哈夫曼树*//*定义数组*//*字符的权值*//*定义结构体*//*定义哈夫曼函数*//*树的初始化*//*构造哈夫曼树的非叶子结点*/{if(myHaffTree[j].parent==0&&myHaffTree[j].weight<s1){s2=s1;x2=x1;s1=myHaffTree[j].weight;x1=j;/*分配摆布结点*/}else if(myHaffTree[j].parent==0&&myHaffTree[j].weight<s2){s2=myHaffTree[j].weight;x2=j;}}myHaffTree[x1].parent=i;myHaffTree[x2].parent=i;myHaffTree[i].weight=s1+s2;myHaffTree[i].lchild=x1;myHaffTree[i].rchild=x2;/*摆布子组合为新树*/}}void HaffmanCode(int n){int start,c,f,i,j,k;char *cd;/*构造n 个结点哈夫曼编码*/cd=(char *)malloc(n*sizeof(char));myHaffCode=(struct Coding *)malloc((n+1)*sizeof(struct Coding));cd[n-1]='\0';for(i=1;i<=n;++i) /*n 个叶子结点的哈夫曼编码*/ {start=n-1;for(c=i,f=myHaffTree[i].parent;f!=0;c=f,f=myHaffTree[f].parent)if(myHaffTree[f].lchild==c) cd[--start]='0';else cd[--start]='1';for(j=start,k=0;j<n;j++){myHaffCode[i].bit[k]=cd[j];k++;}myHaffCode[i].ch=myHaffTree[i].ch; myHaffCode[i].weight=myHaffTree[i].weight; }free(cd);}Init(){int i,n,m;printf("please input the number of words:"); scanf("%d",&n); /*取编码对应的权值*//*定义有返回值的函数*/m=2*n-1;myHaffTree=(struct HaffNode *)malloc(sizeof(struct HaffNode)*(m+1)); for(i=1;i<=n;i++){printf("please input the word and the equal:");scanf("%s%d",&myHaffTree[i].ch,&myHaffTree[i].weight); myHaffTree[i].parent=0;myHaffTree[i].lchild=0;myHaffTree[i].rchild=0;}for(i=n+1;i<=m;i++){myHaffTree[i].ch ='#';myHaffTree[i].lchild=0;myHaffTree[i].parent=0;myHaffTree[i].rchild=0;myHaffTree[i].weight=0;}Haffman(n);HaffmanCode(n);for(i=1;i<=n;i++){printf("%c %d",myHaffCode[i].ch,myHaffCode[i].weight); printf("\n");}printf("init success!\n");return n;}void Caozuo_C(int m){int n,i,j;char string[50],*p;printf("please input the words :"); scanf("%s",string);n=strlen(string);for(i=1,p=string;i<=n;i++,p++){for(j=1;j<=m;j++)if(myHaffCode[j].ch==*p)printf("%s\n",myHaffCode[j].bit); }}void Caozuo_D(int n){int i,c;char code[1000],*p;printf("please input the coding:"); scanf("%s",code);for(p=code,c=2*n-1;*p!='\0';p++) {if(*p=='0'){c=myHaffTree[c].lchild;if(myHaffTree[c].lchild==0){printf("%c",myHaffTree[c].ch);c=2*n-1;continue;/* 编码函数*//*计算字符串长度*/ /*进行编码*//*解码函数*//*输入二进制编码*//*进行解码*//*结束条件*//*赋值*//* 扫描*//*结束*/}}else if(*p=='1'){c=myHaffTree[c].rchild;if(myHaffTree[c].lchild==0){printf("%c",myHaffTree[c].ch);c=2*n-1; /*赋值*/continue;}}}printf("\n");}void main(){int n;char char1;n=Init();printf("A.coding B.codeprintingwhile(1){scanf("%c",&char1);if(char1=='c')break;switch(char1){case'A':Caozuo_C(n);break;case'B':Caozuo_D(n);break;case'C':;break;}}}/*主函数*//*定义字符*//*函数的调用*/C.exit\nplease input the process:\n");/*判断字符*//*执行编码操作*//*执行解码操作*/哈夫曼编码与解码的实现(一)中缀转后缀算法的运行结果:这部份我主要遇到了如下三个问题,其内容与解决方法如下所列:问题1:刚开始不知道如何建一个好树,因为我开始试着建了几个二叉树,不知道什么原因运行的时候那编码总是不对,跟在草稿纸上自己画的那个二叉树总是不相符,就找原因。

哈夫曼编码算法实现完整版

哈夫曼编码算法实现完整版

实验三树的应用一.实验题目:树的应用——哈夫曼编码二.实验内容:利用哈夫曼编码进行通信可以大大提高信道的利用率,缩短信息传输的时间,降低传输成本。

根据哈夫曼编码的原理,编写一个程序,在用户输入结点权值的基础上求哈夫曼编码。

要求:从键盘输入若干字符及每个字符出现的频率,将字符出现的频率作为结点的权值,建立哈夫曼树,然后对各个字符进行哈夫曼编码,最后打印输出字符及对应的哈夫曼编码。

三、程序源代码:#include <iostream.h>#include <fstream.h>#include <string.h>#include <stdlib.h>typedef struct{char data;int weight;int parent,lchild,rchild;}HTNode,*HuffmanTree;typedef char * * HuffmanCode;void Select(HuffmanTree &HT,int n,int m){HuffmanTree p=HT;int tmp;for(int j=n+1;j<=m;j++){int tag1,tag2,s1,s2;tag1=tag2=32767;for(int x=1;x<=j-1;x++){ if(p[x].parent==0&&p[x].weight<tag1){ tag1=p[x].weight;s1=x;}}for(int y=1;y<=j-1;y++){ if(p[y].parent==0&&y!=s1&&p[y].weight<tag2) { tag2=p[y].weight;s2=y;}}if(s1>s2) //将选出的两个节点中的序号较小的始终赋给s1{ tmp=s1; s1=s2; s2=tmp;}p[s1].parent=j;p[s2].parent=j;p[j].lchild=s1;p[j].rchild=s2;p[j].weight=p[s1].weight+p[s2].weight;}}void HuffmanCoding(HuffmanTree &HT,int n,char *w1,int*w2) {int m=2*n-1;if(n<=1) return;HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));HuffmanTree p=HT;for(int i=1;i<=n;i++){ p[i].data=w1[i-1];p[i].weight=w2[i];p[i].parent=p[i].lchild=p[i].rchild=0;}for(;i<=m;i++){ p[i].weight=p[i].parent=p[i].lchild=p[i].rchild=0; } Select(HT,n,m);ofstream outfile; //生成hfmTree文件outfile.open("hfmTree.txt",ios::out);for (i=1;i<=m;i++){outfile<<HT[i].weight<<"\t"<<HT[i].parent<<"\t"<<HT[i]. lchild<<"\t"<<HT[i].rchild<<"\t"<<endl;}outfile.close();cout<<"初始化结果已保存在hfmTree文件中\n";}void ToBeTree() //将正文写入文件ToBeTree中{ofstream outfile;outfile.open("ToBeTree.txt",ios::out);outfile<<"THIS PROGRAM IS MYFAVORITE";outfile.close();}void Encoding(HuffmanTree &HT,int n) //编码{HuffmanCode HC;HC=(HuffmanCode)malloc((n+1)*sizeof(char *));char *cd;cd=(char *)malloc(n*sizeof(char));cd[n-1]='\0';for(int k=1;k<=n;k++){ int start=n-1;for(intc=k,f=HT[k].parent;f!=0;c=f,f=HT[f].parent){ if(HT[f].lchild==c) cd[--start]='0';else cd[--start]='1';}HC[k]=(char *)malloc((n-start)*sizeof(char));strcpy(HC[k],&cd[start]);}cout<<"输出哈夫曼编码:"<<endl;for(int h=1;h<=n;h++) //输出编码{ cout<<HT[h].data<<":";cout<<HC[h];cout<<" ";if (h%8==0) cout<<endl;}cout<<endl<<"输出正文编码:"<<endl;ToBeTree();//读取TOBETREE文件里的正文,并进行编码 fstream infile;infile.open("ToBeTree.txt",ios::in);char s[80];while(!infile.eof()){infile.getline(s,sizeof(s));}infile.close();fstream outfile;outfile.open("CodeFile.txt",ios::out);int count=0;for (h=0;s[h]!='\0';h++){ for(k=1;k<=n;k++)if (s[h]==HT[k].data){ cout<<HC[k];cout<<" ";count++;outfile<<HC[k];break;}if (count%9==0) cout<<endl; //每输出7个换行}outfile.close();cout<<"\n编码结果已保存在文件CodeFile中.";cout<<endl;}void Decoding(HuffmanTree &HT,int n) //译码{int f=2*n-1;fstream infile;infile.open("CodeFile.txt",ios::in);char s[1000];while(!infile.eof()){infile.getline(s,sizeof(s));}infile.close();int i=0;int j=0;fstream outfile;outfile.open("TextFile.txt",ios::out);while(s[i]!='\0'){ f=2*n-1;while(HT[f].lchild!=0)//以f对应的节点的左孩子的值==0作为结束{if (s[j]=='0') f=HT[f].lchild;else f=HT[f].rchild;j++;}i=j;cout<<HT[f].data;outfile<<HT[f].data;}outfile.close();cout<<"\n译码结果已保存在文件TextFile中.";cout<<endl;}void Print() //印代码文件{ int count=0;fstream infile;infile.open("CodeFile.txt",ios::in);char s[1000];while(!infile.eof()){infile.getline(s,sizeof(s));for(int i=0;s[i]!='\0';i++){ cout<<s[i];count++;if (count%50==0) cout<<endl; //在终端上每行显示50个代码}}infile.close();cout<<endl;}char menu() //菜单函数{ cout<<"功能菜单如下:"<<endl;cout<<"* * * * * * * * * * * * * * * * * * * * *"<<endl;cout<<" I:初始化(Initialization) "<<endl;cout<<" E:编码(Encoding) "<<endl;cout<<" D:译码(Decoding) "<<endl;cout<<" P:印代码文件(Print) "<<endl;cout<<" Q:退出(Exit) "<<endl;cout<<"* * * * * * * * * * * * * * * * * * * * *"<<endl;cout<<"请输入功能字符:";char ch;cin>>ch;return ch;}void main(){ int n;int Array[100];char cArray[100];HuffmanTree HT;cout<<"输入n个字符:";cin.getline(cArray,100);n=strlen(cArray);cout<<"一共"<<n<<"个字符.\n";cout<<"依次输入各个字符的权值:"<<endl;for (int i=1;i<=n;i++) cin>>Array[i];int tag;char x=menu();while(1){ switch (x){case 'I':HuffmanCoding(HT,n,cArray,Array);break;case 'E':Encoding(HT,n);break;case 'D':Decoding(HT,n);break;case 'P':Print();break;case 'Q':tag=0;cout<<"结束"<<endl;break;default:cout<<"你输入错误!"<<endl;}if(tag==0) break;cout<<"y(继续) or n(退出)"<<endl;char ch;cin>>ch;if (ch=='y'){ cout<<"请输入功能字符:";char c;cin>>c;x=c;}else exit(1);}}测试数据:用下表给出的字符集和频度的实际统计数据建立哈夫曼树,并实现以下报文的译码和编码:"THIS PROGRAM IS MY FAVORITE".字符空格 A B C D E F G H I J K L M频度 186 64 13 22 32 103 21 15 47 57 1 5 32 20 字符 N O P Q R S T U V W X Y Z 频度 57 63 15 1 48 51 80 23 8 18 1 16 1四.测试结果:如图一所示五.实验体会通过本次实验,尤其在自己对程序的调试过程中,感觉对树的存储结构,终结状态,还有编码,译码的过程都有了比较清晰的认识。

C++实现哈夫曼编码完整代码

C++实现哈夫曼编码完整代码

C++实现哈夫曼编码完整代码#include <iostream>#include <queue>#include <vector>#include <map>#include <string>using namespace std;class Node {public:char c; //表示字符int frequency; //表示该字符出现的次数或频率Node *left;Node *right;Node(char _c, int f, Node *l = NULL, Node *r = NULL):c(_c), frequency(f), left(l), right(r) { }bool operator<(const Node &node) const { //重载<运算法以至于在加入优先队列的时候决定如何处理结点位置return frequency > node.frequency;}};void initNode(priority_queue<Node> &q, int nodeNum) {char c;int frequency;for (int i = 0; i < nodeNum; i++) {cout << "输入字符和结点出现的次数: ";cin >> c >> frequency;Node node(c, frequency);q.push(node);}}void showNode(priority_queue<Node> q) {while (!q.empty()) {Node node = q.top(); q.pop();cout << node.c << ", " << node.frequency << endl;}}//构造哈夫曼树void huffmanTree(priority_queue<Node> &q) {while (q.size() != 1) {Node *left = new Node(q.top()); q.pop();Node *right = new Node(q.top()); q.pop();Node node('R', left->frequency + right->frequency, left, right);q.push(node);}}// 打印哈夫曼编码void huffmanCode(Node *root, string &prefix, map<char, string> &result) { string m_prefix = prefix;if (root->left == NULL)return;//处理左子树prefix += "0";//如果是叶子结点则输出,否则递归打印左子树if (root->left->left == NULL)result[root->left->c] = prefix;//cout << root->left->c << ": " << prefix << endl;elsehuffmanCode(root->left, prefix, result);//还原原来的路径,回溯prefix = m_prefix;//处理右子树prefix += "1";//如果是叶子结点,则输出, 否则递归打印右子树if (root->right->right == NULL)result[root->right->c] = prefix;//cout << root->right->c << ": " << prefix << endl;elsehuffmanCode(root->right, prefix, result);}void testResult(map<char, string> result) {//迭代map容器map<char, string>::const_iterator it = result.begin(); while (it != result.end()) {cout << it->first << ": " << it->second << endl;++it;}}int main() {priority_queue<Node> q;int nodeNum;//初始化字符信息cout << "请输入结点个数: ";cin >> nodeNum;initNode(q, nodeNum);//showNode(q);//构造哈夫曼树huffmanTree(q);//构造哈夫曼编码Node root = q.top();string prefix = "";map<char, string> result;huffmanCode(&root, prefix, result);//检验结果是否正确testResult(result);return 0;}。

哈夫曼编码实验超详尽版

哈夫曼编码实验超详尽版

编码步骤
6



在F中选取两棵根结点权值最小的树作为新构造 的二叉树的左右子树,新二叉树的根结点的权 值为其左右子树的根结点的权值之和。 从F中删除这两棵树,并把这棵新的二叉树同样 以升序排列加入到集合F中。 重复二和三两步,直到集合F中只有一棵二叉树 为止。
示例
7

假如有A,B,C,D,E五个字符,出现的频率(即权值) 分别为5,4,3,2,1,那么我们第一步先取两个最小权值 作为左右子树构造一个新树,即取1,2构成新树, 其结点为1+2=3,如图:
原理
3

首先统计信源中各符号出现的概率,按符号出现的
概率从大到小排序; 把最小的两个概率相加合并成新的概率,与剩余的 概率组成新的概率集合; 对新的概率集合重新排序,再次把其中最小的两个 概率相加,组成新的概率集合。如此重复进行,直 到最后两个概率的和为l;原理4 Nhomakorabea
分配码字:码字分配从最后一步开始反向进行,
9


实现过程:首先通过 HuffmanTree() 函数构造哈夫 曼树,然后在主函数 main()中自底向上开始(也就 是从数组序号为零的结点开始)向上层层判断,若 在父结点左侧,则置码为 0,若在右侧,则置码为 1。 最后输出生成的编码。 typedef struct
{ int bit[MAXBIT]; int start; } HCodeType; /* 编码结构体 */
五、程序部分代码及其分析
13
/* 设置找到的两个子结点 x1、x2 的父结点信息 */ HuffNode[x1].parent = n+i; HuffNode[x2].parent = n+i; HuffNode[n+i].weight = HuffNode[x1].weight + HuffNode[x2].weight; HuffNode[n+i].lchild = x1; HuffNode[n+i].rchild = x2;

c++哈夫曼编码的实现

c++哈夫曼编码的实现

c++哈夫曼编码的实现=================哈夫曼编码是一种非常有效的数据压缩算法,它的主要思想是通过统计数据中各种符号的频率来构建一棵哈夫曼树,从而实现对原始数据的编码。

在C语言中,我们可以使用动态规划来实现哈夫曼编码。

一、哈夫曼编码的基本原理--------------哈夫曼编码是一种可变长度编码,其编码长度取决于原始数据中各个符号的频率。

频率越高的符号,其编码长度越短。

通过统计数据中各个符号的出现频率,我们可以构建出一棵哈夫曼树,这棵树中的每个节点都代表一个符号,节点的权值就是该符号的频率。

通过遍历哈夫曼树,我们可以得到每个符号的编码,从而实现数据的压缩。

二、C语言实现哈夫曼编码------------下面是一个简单的C语言程序,实现了哈夫曼编码的功能:```c#include <stdio.h>#include <stdlib.h>#include <stdbool.h>#define MAX_SYMBOL_COUNT 100 // 最大符号数量#define HUF_TREE_DEPTH 3 // 哈夫曼树深度为3typedef struct Node {char symbol; // 符号struct Node* left; // 左子节点struct Node* right; // 右子节点double frequency; // 频率} Node;// 创建新节点Node* createNode(char symbol, double frequency) {Node* node = (Node*)malloc(sizeof(Node));node->symbol = symbol;node->frequency = frequency;node->left = NULL;node->right = NULL;return node;}// 构建哈夫曼树Node* buildHuffmanTree(char* symbols, int symbolCount) { // 根据频率进行排序,从小到大排列double frequencies[MAX_SYMBOL_COUNT];for (int i = 0; i < symbolCount; i++) {frequencies[i] = symbols[i] == ' ' ? 0.0 : symbols[i] ? symbols[i] : -1; // 检查字符是否存在}qsort(frequencies, symbolCount, sizeof(double), compare); // 使用qsort进行排序Node* root = NULL; // 根节点为空,需要手动构建哈夫曼树int index = 0; // 下一个需要创建节点的索引(0到symbolCount-1之间)double currentFrequency = frequencies[index]; // 当前节点频率(如果不为空)while (index < symbolCount){ // 遍历所有符号和频率,直到遍历完为止if (root == NULL){ // 如果根节点为空,创建根节点并指向当前节点root = createNode(NULL, currentFrequency);} else{ // 如果根节点不为空,查找下一个需要创建节点的索引和当前节点频率是否小于当前节点频率的倒数index++; // 下一个需要创建节点的索引增加一个位置(包括当前节点)if (frequencies[index] / currentFrequency <1.0 / HUF_TREE_DEPTH) { // 如果满足条件,创建新的子节点并递归构建哈夫曼树(当前节点)Node* child = createNode(symbols[index], frequencies[index]); // 创建子节点并保存符号和频率信息if (root->left == NULL){ // 如果当前节点的左子节点为空,将当前节点设置为左子节点并递归构建哈夫曼树(左子树)root->left = child;} else{ // 如果当前节点的右子节点为空,将当前节点设置为右子节点并递归构建哈夫曼树(右子树)root->right = child;} // 更新根节点的左右子节点信息并递归构建哈夫曼树(父节点)} else{ // 如果当前节点不足以生成新的子节点(由于被优先排序)继续处理下一个节点 currentFrequency = frequencies[index]; // 将当前节点的频率设置为下一个需要创建节点的频率(避免重复处理同一个符号)} // 更新索引和当前频率信息(继续处理下一个符号)} // 结束while循环(处理完所有符号和频率)}。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

实验三树的应用一.实验题目:树的应用——哈夫曼编码二.实验内容:利用哈夫曼编码进行通信可以大大提高信道的利用率,缩短信息传输的时间,降低传输成本。

根据哈夫曼编码的原理,编写一个程序,在用户输入结点权值的基础上求哈夫曼编码。

要求:从键盘输入若干字符及每个字符出现的频率,将字符出现的频率作为结点的权值,建立哈夫曼树,然后对各个字符进行哈夫曼编码,最后打印输出字符及对应的哈夫曼编码。

三、程序源代码:#include <iostream.h>#include <fstream.h>#include <string.h>#include <stdlib.h>typedef struct{char data;int weight;int parent,lchild,rchild;}HTNode,*HuffmanTree;typedef char * * HuffmanCode;void Select(HuffmanTree &HT,int n,int m){HuffmanTree p=HT;int tmp;for(int j=n+1;j<=m;j++){int tag1,tag2,s1,s2;tag1=tag2=32767;for(int x=1;x<=j-1;x++){ if(p[x].parent==0&&p[x].weight<tag1){ tag1=p[x].weight;s1=x;}}for(int y=1;y<=j-1;y++){ if(p[y].parent==0&&y!=s1&&p[y].weight<tag2){ tag2=p[y].weight;s2=y;}}if(s1>s2) //将选出的两个节点中的序号较小的始终赋给s1{ tmp=s1; s1=s2; s2=tmp;}p[s1].parent=j;p[s2].parent=j;p[j].lchild=s1;p[j].rchild=s2;p[j].weight=p[s1].weight+p[s2].weight;}}void HuffmanCoding(HuffmanTree &HT,int n,char *w1,int*w2){int m=2*n-1;if(n<=1) return;HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));HuffmanTree p=HT;for(int i=1;i<=n;i++){ p[i].data=w1[i-1];p[i].weight=w2[i];p[i].parent=p[i].lchild=p[i].rchild=0;}for(;i<=m;i++){ p[i].weight=p[i].parent=p[i].lchild=p[i].rchild=0; }Select(HT,n,m);ofstream outfile; //生成hfmTree文件outfile.open("hfmTree.txt",ios::out);for (i=1;i<=m;i++){outfile<<HT[i].weight<<"\t"<<HT[i].parent<<"\t"<<HT[i].lchild<<"\t"<<HT[i].rchild<<"\t"<<endl;}outfile.close();cout<<"初始化结果已保存在hfmTree文件中\n";}void ToBeTree() //将正文写入文件ToBeTree中{ofstream outfile;outfile.open("ToBeTree.txt",ios::out);outfile<<"THIS PROGRAM IS MYFA VORITE";outfile.close();}void Encoding(HuffmanTree &HT,int n) //编码{HuffmanCode HC;HC=(HuffmanCode)malloc((n+1)*sizeof(char *));char *cd;cd=(char *)malloc(n*sizeof(char));cd[n-1]='\0';for(int k=1;k<=n;k++){ int start=n-1;for(int c=k,f=HT[k].parent;f!=0;c=f,f=HT[f].parent){ if(HT[f].lchild==c) cd[--start]='0';else cd[--start]='1';}HC[k]=(char *)malloc((n-start)*sizeof(char));strcpy(HC[k],&cd[start]);}cout<<"输出哈夫曼编码:"<<endl;for(int h=1;h<=n;h++) //输出编码{ cout<<HT[h].data<<":";cout<<HC[h];cout<<" ";if (h%8==0) cout<<endl;}cout<<endl<<"输出正文编码:"<<endl;ToBeTree();//读取TOBETREE文件里的正文,并进行编码fstream infile;infile.open("ToBeTree.txt",ios::in);char s[80];while(!infile.eof()){infile.getline(s,sizeof(s));}infile.close();fstream outfile;outfile.open("CodeFile.txt",ios::out);int count=0;for (h=0;s[h]!='\0';h++){ for(k=1;k<=n;k++)if (s[h]==HT[k].data){ cout<<HC[k];cout<<" ";count++;outfile<<HC[k];break;}if (count%9==0) cout<<endl; //每输出7个换行}outfile.close();cout<<"\n编码结果已保存在文件CodeFile中.";cout<<endl;}void Decoding(HuffmanTree &HT,int n) //译码{int f=2*n-1;fstream infile;infile.open("CodeFile.txt",ios::in);char s[1000];while(!infile.eof()){infile.getline(s,sizeof(s));}infile.close();int i=0;int j=0;fstream outfile;outfile.open("TextFile.txt",ios::out);while(s[i]!='\0'){ f=2*n-1;while(HT[f].lchild!=0)//以f对应的节点的左孩子的值==0作为结束{if (s[j]=='0') f=HT[f].lchild;else f=HT[f].rchild;j++;}i=j;cout<<HT[f].data;outfile<<HT[f].data;}outfile.close();cout<<"\n译码结果已保存在文件TextFile中.";cout<<endl;}void Print() //印代码文件{ int count=0;fstream infile;infile.open("CodeFile.txt",ios::in);char s[1000];while(!infile.eof()){infile.getline(s,sizeof(s));for(int i=0;s[i]!='\0';i++){ cout<<s[i];count++;if (count%50==0) cout<<endl; //在终端上每行显示50个代码}}infile.close();cout<<endl;}char menu() //菜单函数{ cout<<"功能菜单如下:"<<endl;cout<<"* * * * * * * * * * * * * * * * * * * * *"<<endl;cout<<" I:初始化(Initialization) "<<endl;cout<<" E:编码(Encoding) "<<endl;cout<<" D:译码(Decoding) "<<endl;cout<<" P:印代码文件(Print) "<<endl;cout<<" Q:退出(Exit) "<<endl;cout<<"* * * * * * * * * * * * * * * * * * * * *"<<endl;cout<<"请输入功能字符:";char ch;cin>>ch;return ch;}void main(){ int n;int Array[100];char cArray[100];HuffmanTree HT;cout<<"输入n个字符:";cin.getline(cArray,100);n=strlen(cArray);cout<<"一共"<<n<<"个字符.\n";cout<<"依次输入各个字符的权值:"<<endl;for (int i=1;i<=n;i++) cin>>Array[i];int tag;char x=menu();while(1){ switch (x){case 'I':HuffmanCoding(HT,n,cArray,Array);break;case 'E':Encoding(HT,n);break;case 'D':Decoding(HT,n);break;case 'P':Print();break;case 'Q':tag=0;cout<<"结束"<<endl;break;default:cout<<"你输入错误!"<<endl;}if(tag==0) break;cout<<"y(继续) or n(退出)"<<endl;char ch;cin>>ch;if (ch=='y'){ cout<<"请输入功能字符:";char c;cin>>c;x=c;}else exit(1);}}测试数据:用下表给出的字符集和频度的实际统计数据建立哈夫曼树,并实现以下报文的译码和编码:"THIS PROGRAM IS MY FAVORITE".字符空格 A B C D E F G H I J K L M频度186 64 13 22 32 103 21 15 47 57 1 5 32 20字符N O P Q R S T U V W X Y Z频度57 63 15 1 48 51 80 23 8 18 1 16 1四.测试结果:如图一所示五.实验体会通过本次实验,尤其在自己对程序的调试过程中,感觉对树的存储结构,终结状态,还有编码,译码的过程都有了比较清晰的认识。

相关文档
最新文档