首页IT科技利用哈夫曼编码进行字符串压缩(哈夫曼应用)

利用哈夫曼编码进行字符串压缩(哈夫曼应用)

时间2025-05-06 04:15:14分类IT科技浏览4618
导读:哈夫曼编码应用 问题描述...

哈夫曼编码应用

问题描述

​ 给定字符串          ,将每个不同的字符的哈夫曼编码表示并输出其哈夫曼编码              ,并再将其哈夫曼编码还原回字符串

分析一下

构建哈夫曼树

​ 使用静态链表      ,先将所有的结点关系全部清零        ,再进行结点和相应权值的赋值             ,遍历后n-1个结点 (新根)         ,从n个结点中选两个最小的权值了合成一棵树      ,并将新根加入到比较结点中(并将这两棵树标记以及结合             ,不再进行下次的比较)           ,最后后合成一颗哈夫曼树

哈夫曼编码

​ 在这里用到了一个大数组嵌套一个小数组   ,大数组I的功能是存放每一个结点的哈夫曼编码              ,小数组中存放每一个结点的没有个哈夫曼编码的反码

​ 从叶子结点分别向根出发即可             ,若该结点时双亲结点的左孩子,则记0            ,反之记为1               ,记录在一个记录数组中直到该结点没有双亲(根结点)   ,每遍历完一个结点后将记录数组复制到对应的小数组中          。并及时清空记录数组进行下次使用                。

​ 在输出方面使用了多重的for循环          ,依次遍字符串              ,将字符串的每一个字符与结点进行比较      ,若相等则输出对应的(该结点)的哈夫曼编码        ,最后再用一数组接收             ,以便后续的使用

解码

​ 依次遍历没有过哈夫曼遍历         ,从根结点出发      ,遇0向左             ,遇1则右           ,若到了叶子(无左孩子或无右孩子)   ,则输出    。并将更新结点值

看看代码吧

必没问题!!!(有问题就用个dev吧...)

#include<iostream> #define Max_S 1000000 #define MaxSize 100 using namespace std; //静态链表 typedef struct TreeNode{ char data; int weight; int parent,lchild,rchild; }HTNode, *HuffmanTree; //编码数组 typedef struct{ int HC[MaxSize]; }info,*Info;//一个大数组套一个小数组 //=========================================================== //一些串和二叉树的算法 //求串长 int Strstrlen(char a[]){ int i = 1; for(;a[i] !=\0;){ i++; } return i; } //字符串赋值 void StrAssige(char(&S)[MaxSize+1],char a[]){ S[0] = Strstrlen(a); for(int i = 1;i <= Strstrlen(a);i++){ S[i] = a[i-1]; } } //求深度 int qiushendu(HuffmanTree t,int root){ if(root == 0) return 0; if(t[root].lchild == 0&&t[root].rchild == 0) return 1; return (max(qiushendu(t,t[root].lchild),qiushendu(t,t[root].rchild)) + 1); } //================================================================== //获取两个最小值 int *Select(HuffmanTree HT,int n){ int s1,s2;////最小值与极小值 int mmin = Max_S;//先等于无穷大 int min = Max_S; for(int i = 1;i <= n;i++){ if(HT[i].parent != 0) continue;//双亲不为零代表已经构成新树              ,应去除 else{ if(mmin >= HT[i].weight){//最小的 min = mmin ; s2 = s1; mmin = HT[i].weight; s1 = i; }else if(min >= HT[i].weight){//次小的 min = HT[i].weight; s2 = i; } } } //若最小值相等             ,则浅(先遍历的)树的序号在前 int S1 = qiushendu(HT,s1); int S2 = qiushendu(HT,s2); if(S1 >= S2){ int temp; temp = s1; s1 = s2; s2 = temp;//交换顺序 } //用数组存放最小值和次小值 int a[3] = {0,s1,s2}; return a; } //=========================================================================== //构建哈夫曼树 void CreatHuffmanTree(HuffmanTree &HT,char *huf,int *wei,int n){ int s1,s2;//最小值与极小值 if(n <= 1){ cout << "抱歉,您输入的结点数不符合逻辑"; return; } int m = 2*n-1;//总结点树 HT = new HTNode[m+1];//放弃下标为零的数组 //先遍历前n个数,初始化 for(int i = 1;i <= m;i++){//全部初始化为零 HT[i].parent = 0; HT[i].lchild = 0; HT[i].rchild = 0; } //赋结点          、权值 for(int i;i <= n;i++){ HT[i].data = huf[i];//结点 HT[i].weight = wei[(int)huf[i]];//权值 } //遍历后n+1个            ,新根 for(int i = n+1;i <= m;i++){ //找出最小额两个结点 int *a;//获取s1和s2 a = Select(HT,i-1);//在n个数中找 s1 = a[1]; s2 = a[2]; //更新各个数值 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 HuffmanCode(HuffmanTree HT,info* I, int n){ int lchild,rchilg,parent,copyparent;//左孩子值   ,有孩子子          ,双亲值              ,类双亲值(永远是双亲值值的孩子      ,但不知是左孩子右) int jilv[100];//记录数组每个结点的编码(0/1)        ,算深度即可无需大开 for(int i = 1;i <= n;i++){//依次遍历叶子结点 int n = 0;//记录数 //初始化各个双亲值 copyparent = i; parent = HT[i].parent; while(parent != 0&&copyparent != 0){//两个双亲都不为零 if(HT[parent].lchild == copyparent){//结点的双亲的左孩子与他的序号相等             ,记为零 jilv[++n] = 0; }else{ jilv[++n] = 1; } copyparent = parent;//更新类双亲 parent = HT[parent].parent;//更新双亲 } I[i].HC[0] = jilv[0] = n;//第一个字符的总编码数 for(int m = 1;m <= jilv[0];m++)//将第一个字符的所有编码复制到第一个存在数组中去 I[i].HC[m] = jilv[m]; //输出 cout << HT[i].data << ":"; for(int m = jilv[0];m >=1;m--){//反向输出 cout << I[i].HC[m]; jilv[m] = 0;//记录数组清空 } cout << endl; jilv[0] = 0;//记录数组清零 } } //完整输出哈夫曼编码 int *printHuf(char *h,char *huf,info* I){ static int hufman[MaxSize+1]; int mum = 0; for(int i = 1;i <= h[0];i++){//遍历原数组 for(int j = 1;j <= huf[0];j++){//遍历结点 if(h[i] == huf[j]){//如果相等 for(int m = I[j].HC[0];m >=1;m--){//反向输出 cout << I[j].HC[m]; hufman[++mum] = I[j].HC[m]; } } } } hufman[0] = mum; return hufman; } //================================================================================== //哈夫曼解码         ,并输出 void HuffmanDeCode(int * HufMan,HuffmanTree HT,int n){ HuffmanTree p = HT; int lchild,rchid,r,m = 2*n-1; for(int i = 1;i <= HufMan[0];i++){//遍历每一个哈夫曼编码 //与0向左      ,由1向右 if(HufMan[i] == 0){ m = p[m].lchild; }else{ m = p[m].rchild; } //若无孩子则直接输出(没有度为一的数)             ,并更新根结点和m的值 if(p[m].lchild == 0||p[m].rchild == 0){ cout << p[m].data; p = HT; m = 2*n- 1; } } } int main(){ int wei[1000] = {0};//权值数组 char huf[MaxSize+1];//哈夫曼结点数组 char a[MaxSize+1];//赋值串 char h[MaxSize+1];//要编译的字符串 cout << "请输入要编码的字符:"; gets(a); StrAssige(h,a); //赋结点              、权值 for(int i = 1,n = 0;i <=h[0];i++){ wei[(int)h[i]]++;//权值++ if(wei[(int)h[i]] == 1){//第一次遇到的不同得字符 huf[++n] = h[i];//结点确定 } huf[0] = n;//总结点数 } //哈夫曼树 HuffmanTree HT; //创建哈夫曼树 CreatHuffmanTree(HT,huf,wei,huf[0]); //====================================================================================== //将字符串哈夫曼编码化,并输出每个结点的哈夫曼编码 info *I = new info[huf[0]];//就是一个大数组           ,大数组存放每一个字符的哈夫曼编码   ,小数组存放每一位的 HuffmanCode(HT,I,huf[0]); //输出完整的哈夫曼编码 ,并捕获 int* HufMan; cout << "获得的哈夫曼编码为:"; HufMan = printHuf(h,huf,I); cout << endl; //================================================================================== //解码哈夫曼编码 cout << "该哈夫曼编码的解码为:"; HuffmanDeCode(HufMan,HT,huf[0]); cout <<endl; return 0; }

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
windows 11 build 22621(Win11 Build 23430 预览版发布(附更新修复内容汇总))