C语言实现压缩二例

一 简单字符串压缩

编写一个字符串压缩程序,将字符串中连续出席的重复字母进行压缩,并输出压缩后的字符串。

压缩规则:

1、仅压缩连续重复出现的字符。比如字符串”abcbc”由于无连续重复字符,压缩后的字符串还是”abcbc”。 
2、压缩字段的格式为”字符重复的次数+字符”。例如:字符串”xxxyyyyyyz”压缩后就成为”3x6yz”。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <stdlib.h>  
  4.   
  5. int main()  
  6. {   
  7.     char str[100] = {'\0'};  
  8.     char res[100] = {'\0'};  
  9.     scanf("%s",str);  
  10.     int length = strlen(str);  
  11.     int i=0, j=0, k=0;  
  12.     int count = 0;  
  13.     do  
  14.     {  
  15.         if(i < length && str[i++] == str[j])  
  16.             count++;  
  17.         if(str[i] != str[j])  
  18.         {  
  19.             if(count <= 1)  
  20.                 res[k++] = str[j];  
  21.             else  
  22.             {  
  23.                 if(count > 1)  
  24.                 {  
  25.                     char temp[10] = {'\0'};  
  26.                     itoa(count,temp,10);  
  27.                     strcpy(res+k,temp);  
  28.                     k+=strlen(temp);  
  29.                     res[k++] = str[j];  
  30.                 }  
  31.             }  
  32.             j = i;  
  33.             count = 0;  
  34.         }  
  35.     }while(i<length);  
  36.     res[k] = '\0';  
  37.     printf("The result is : %s\n",res);  
  38.     return 0;  
  39. }  


运行情况:

二 哈夫曼编码

哈夫曼树─即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩。 在计算机信息处理中,
“哈夫曼编码”是一种一致性编码法(又称“熵编码法”),用于数据的无损耗压缩。这一术语是指使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码。这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的(出现概率高的字符使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而达到无损压缩数据的目的)。这种方法是由David.A.Huffman发展起来的。 例如,在英文中,e的出现概率很高,而z的出现概率则最低。当利用哈夫曼编码对一篇英文进行压缩时,e极有可能用一个位
哈弗曼编码在信息论中应用举例哈弗曼编码在信息论中应用举例
(bit)来表示,而z则可能花去25个位(不是26)。用普通的表示方法时,每个英文字母均占用一个字节(byte),即8个位。二者相比,e使用了一般编码的1/8的长度,z则使用了3倍多。若能实现对于英文中各个字母出现概率的较准确的估算,就可以大幅度提高无损压缩的比例。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //用C语言实现Huffman编码,并计算本节中块的编码  
  2. //长度(以位为单位),计算Huffman编码的压缩比。  
  3. //主程序:  
  4. #include<stdio.h>  
  5. #include<stdlib.h>  
  6.   
  7. typedef struct HfTreeNode  
  8. {  
  9.     int weight; //权重  
  10.     int parent; //父节点  
  11.     int lchild, rchild;   //两个子节点  
  12. }Struct, *HfStruct;  
  13.   
  14. typedef struct{  
  15.     char code[10];  
  16.     int start;  
  17. }HCodeType;  
  18.   
  19. void quanDCT(short(*data)[8], short(*result)[8]);//量化函数  
  20. int calWeight(short(*result), int(*Node), int(*Weight));//权重计算  
  21. void print_data_screen(short data[8][8]);//数据打印  
  22.   
  23. //待编码数据  
  24. short DctData[8][8] = {  
  25.     { 1149, 38, -43, -10, 25, -83, 10, 40 },  
  26.     { -81, -3, 114, -73, -6, -2, 21, -5 },  
  27.     { 13, -11, 0, -42, 25, -3, 16, -38 },  
  28.     { 1, -61, -13, -12, 35, -23, -18, 4 },  
  29.     { 43, 12, 36, -4, 9, -21, 6, -8 },  
  30.     { 35, -11, -9, -4, 19, -28, -21, 13 },  
  31.     { -19, -7, 20, -6, 2, 2, 11, -21 },  
  32.     { -5, -13, -11, -17, -4, -1, 6, -4 } };  
  33.   
  34. HfStruct create_HuffmanTree(int *WeightPoint, int n);//霍夫曼树创建函数  
  35. void HuffmanCoding(HfStruct HT, HCodeType HuffCode[], int n);//霍夫曼编码函数  
  36.   
  37. void main()  
  38. {  
  39.     int i, j;//循环变量  
  40.     int Length;//编码节点数  
  41.     int totalbits = 0;//计算编码后的总的比特数  
  42.   
  43.     int Node[64];//节点数组  
  44.     int Weight[64];//权重数组  
  45.   
  46.     short QuanResult[8][8];//量化结果存储  
  47.     quanDCT(DctData, QuanResult);//数据量化  
  48.     printf("量化后的数据:\n");//打印量化数据  
  49.     print_data_screen(QuanResult);  
  50.   
  51.     Length = calWeight(*QuanResult, Node, Weight);//计算量化数据的节点与权重,并返回节点数  
  52.   
  53.     int *maNode = (int*)malloc(Length*sizeof(int));//按有效节点进行分配  
  54.     int *maWeight = (int*)malloc(Length*sizeof(int));//按有效节点进行分配  
  55.     for (i = 0; i<Length; i++)  
  56.     {  
  57.         *(maNode + i) = Node[i];//拷贝有效节点  
  58.         *(maWeight + i) = Weight[i];//拷贝有效权重  
  59.     }  
  60.   
  61.   
  62.     //根据权重与有效节点数创建霍夫曼树  
  63.     HfStruct p = create_HuffmanTree(maWeight, Length);  
  64.   
  65.     //打印霍夫曼树  
  66.     printf("霍夫曼树:\n");  
  67.     for (i = 0; i<2 * Length - 1; i++)  
  68.         printf("父节点:%3d,左子节点:%3d,右子节点:%3d,权重:%3d\n", p[i].parent, p[i].lchild, p[i].rchild, p[i].weight);  
  69.   
  70.   
  71.     HCodeType code[9];  
  72.   
  73.     //依据霍夫曼树进行编码  
  74.     HuffmanCoding(p, code, Length);//霍夫曼编码  
  75.   
  76.     //打印出编码结果  
  77.     printf("\n编码结果:\n");  
  78.     for (i = 0; i<Length; i++)  
  79.     {  
  80.         printf("节点:%3d,权重:%3d,编码:", *(maNode + i), *(maWeight + i));  
  81.         for (j = code[i].start + 1; j < Length; j++)  
  82.             printf("%c", code[i].code[j]);  
  83.         printf("\n");  
  84.     }  
  85.   
  86.     //计算编码后的总的比特数,计算压缩比  
  87.     for (i = 0; i<Length; i++)  
  88.     {  
  89.         j = Length - 1 - code[i].start;  
  90.         totalbits = totalbits + maWeight[i] * j;  
  91.     }  
  92.     printf("\n编码后的总位数为:%d,压缩比为:%4.2f\n", totalbits, (double)(64 * 8) / totalbits);  
  93.   
  94.     while (1);  
  95. }  
  96.   
  97. short QuanTable[8][8] = {  
  98.     { 16, 11, 10, 16, 24, 40, 51, 61 },  
  99.     { 12, 12, 14, 19, 26, 58, 60, 55 },  
  100.     { 14, 13, 16, 24, 40, 57, 69, 56 },  
  101.     { 14, 17, 22, 29, 51, 87, 80, 62 },  
  102.     { 18, 22, 37, 56, 68, 109, 103, 77 },  
  103.     { 24, 35, 55, 64, 81, 104, 113, 92 },  
  104.     { 49, 64, 78, 87, 103, 121, 120, 101 },  
  105.     { 72, 92, 95, 98, 112, 100, 103, 99 }  
  106. };//量化表  
  107.   
  108. void print_data_screen(short data[8][8])//数据打印  
  109. {  
  110.     int x, y;  
  111.     for (x = 0; x<8; x++)  
  112.         for (y = 0; y<8; y++)  
  113.         {  
  114.             printf("%d", data[x][y]);  
  115.             if (y == 7)  
  116.             {  
  117.                 if (x == 7)  
  118.                     printf("\n\n");  
  119.                 else  
  120.                     printf("\n");  
  121.             }  
  122.             else  
  123.             {  
  124.                 printf(",");  
  125.             }  
  126.         }  
  127.   
  128. }  
  129.   
  130.   
  131. void quanDCT(short(*data)[8], short(*result)[8])//数据量化  
  132. {  
  133.     int x, y;  
  134.     for (x = 0; x<8; x++)  
  135.     {  
  136.         for (y = 0; y<8; y++)  
  137.         {  
  138.             *(*(result + x) + y) = (short)(double(*(*(data + x) + y)) / QuanTable[x][y] + 0.5);  
  139.         }  
  140.     }  
  141. }  
  142.   
  143.   
  144. int calWeight(short(*result), int *Node, int *Weigh)//计算权重  
  145. {  
  146.     int x, y, i, find = 0;  
  147.     for (x = 0; x<64; x++)  
  148.     {  
  149.         Node[x] = 0;  
  150.         Weigh[x] = 0;  
  151.     }  
  152.   
  153.     Node[0] = (*result);  
  154.     Weigh[0] = 1;  
  155.     i = 0;  
  156.     for (x = 1; x<64; x++)  
  157.     {  
  158.         for (y = 0; y <= i; y++)  
  159.         {  
  160.             if (*(x + result) == Node[y])  
  161.             {  
  162.                 Weigh[y]++;  
  163.                 find = 1;  
  164.                 break;  
  165.             }  
  166.         }  
  167.         if (find)  
  168.         {  
  169.             find = 0;  
  170.             continue;  
  171.         }  
  172.         else  
  173.         {  
  174.             i++;  
  175.             Node[y] = *(x + result);  
  176.             Weigh[y]++;  
  177.         }  
  178.     }  
  179.   
  180.     return i + 1;  
  181.   
  182. }  
  183.   
  184.   
  185. /* 
  186. 从HtStruct选出权重最小,并且没有父节点的节点 
  187. */  
  188. int WeightMinNode(HfStruct HtStruct, int Mum)  
  189. {  
  190.     int i = 0;  //序号, 循环用  
  191.     int min;        //最小权重序号  
  192.     int MinWeight; //最小权重  
  193.   
  194.     //首先选择一个节点,用于比较出最小的一个  
  195.     while (HtStruct[i].parent != -1)  
  196.         i++;  
  197.     MinWeight = HtStruct[i].weight;  
  198.     min = i;  
  199.   
  200.     //选出weight最小且parent为-1的元素,并将其序号赋给min    
  201.     for (; i<Mum; i++)  
  202.     {  
  203.         if (HtStruct[i].weight<MinWeight&&HtStruct[i].parent == -1)  
  204.         {  
  205.             MinWeight = HtStruct[i].weight;  
  206.             min = i;  
  207.         }  
  208.     }  
  209.   
  210.     //选出weight最小的元素后,将其parent置1,使得下一次比较时将其排除在外。  
  211.     HtStruct[min].parent = 1;  
  212.   
  213.     return min;  
  214. }  
  215.   
  216.   
  217. /* 
  218. 从HtStruct数组的前k个元素中选出weight最小且parent为-1的两个,分别将其序号保存在min1和min2中 
  219. */  
  220. void ChoseMinium2(HfStruct HtStruct, int Mum, int *min1, int *min2)  
  221. {  
  222.     *min1 = WeightMinNode(HtStruct, Mum);  
  223.     *min2 = WeightMinNode(HtStruct, Mum);  
  224. }  
  225.   
  226. /* 
  227. 根据给定的n个权值构造一棵赫夫曼树 
  228. */  
  229. HfStruct create_HuffmanTree(int *WeightPoint, int n)  
  230. {  
  231.     //一棵有n个叶子节点的赫夫曼树共有2n-1个节点  
  232.     int AllNodeNum = 2 * n - 1;  
  233.     HfStruct HT = (HfStruct)malloc(AllNodeNum*sizeof(Struct));  
  234.     int i;  
  235.   
  236.     //叶子节点初始化,将传入的数据加载到叶子节点上  
  237.     for (i = 0; i<n; i++)  
  238.     {  
  239.         HT[i].parent = -1;  
  240.         HT[i].lchild = -1;  
  241.         HT[i].rchild = -1;  
  242.         HT[i].weight = *WeightPoint;  
  243.         WeightPoint++;  
  244.     }  
  245.   
  246.     //HT[n],HT[n+1]...HT[2n-2]中存放的是中间构造出的每棵二叉树的根节点  
  247.     for (; i<AllNodeNum; i++)  
  248.     {  
  249.         HT[i].parent = -1;  //父节点初始化  
  250.         HT[i].lchild = -1;  //左子节点初始化  
  251.         HT[i].rchild = -1;  //右子节点初始化  
  252.         HT[i].weight = 0;   //权重初始化  
  253.     }  
  254.   
  255.     int min1, min2;  
  256.     int *ad_min1 = &min1;//用于传递最小权重的节点  
  257.     int *ad_min2 = &min2; //用于传递最小权重的节点  
  258.   
  259.     //每一轮比较后选择出min1和min2构成一课二叉树,最后构成一棵赫夫曼树  
  260.     for (i = n; i<AllNodeNum; i++)  
  261.     {  
  262.         ChoseMinium2(HT, i, ad_min1, ad_min2); //选出权重最小的两个节点  
  263.         HT[min1].parent = i;  //父节点赋值  
  264.         HT[min2].parent = i;  //父节点赋值  
  265.         HT[i].lchild = min1;  //左子节点赋值  
  266.         HT[i].rchild = min2;  //右子节点赋值  
  267.         HT[i].weight = HT[min1].weight + HT[min2].weight;  //权重为两个子节点权重之和  
  268.     }  
  269.     return HT;  
  270. }  
  271. /* 
  272. 从叶子节点到根节点逆向求赫夫曼树HT中n个叶子节点的赫夫曼编码,并保存在code中 
  273. */  
  274. void HuffmanCoding(HfStruct HT, HCodeType HuffCode[], int n)  
  275. {  
  276.     HCodeType cd;  
  277.     int i,j,current,father;  
  278.       
  279.     for (i = 0; i<n; i++)  
  280.     {  
  281.         cd.start = n - 1;  
  282.         current = i;           //定义当前访问的节点  
  283.         father = HT[i].parent; //当前节点的父节点  
  284.   
  285.         //从叶子节点向上搜索  
  286.         while (father != -1)  
  287.         {  
  288.             if (HT[father].lchild == current)   //如果是左子节点,则编码为0           
  289.                 cd.code[cd.start--] = '0';  
  290.             else//如果是右子节点,则编码为1           
  291.                 cd.code[cd.start--] = '1';  
  292.   
  293.             current = father;  
  294.             father = HT[father].parent;  
  295.         }  
  296.         for (j = cd.start + 1; j <n; j++)  
  297.             HuffCode[i].code[j] = cd.code[j];  
  298.         HuffCode[i].start = cd.start;  
  299.     }     
  300. }  

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值