- /**********************************************************************************
- 46. 设有一个字符串,长度小于 100,且全部以英文字母组成。对字串中的每个字
- 母可用 0,1,2 三个数字进行编码,且数字可以重复使用。
- 程序要求:(1) 输入字符串,并能判断输入是否有错;
- (2) 输出对应的编码表及码长,要求字串的编码总长度为最短;
- (3) 根据上述编码表,给出一些编码,然后求出其原字符串。
- 例如:输入的字符为:ABCBAAADDEF
- 其对应的编码表为:
- A: 2 B: 10
- C: 11 D: 12
- E: 00 F: 01
- 对应的编码为:210111022212120001 总码长为:18
- 根据该编码,给出编码:010001121110222 则输出字串:FEFDCBAAA.
- *******************************************************************************/
- #include <stdio.h>
- #include <malloc.h>
- //英文字母的个数
- #define LETTER_NUM 26
- //编码树节点
- typedef struct
- {
- int weight;
- int parent;
- int child0;
- int child1;
- int child2;
- } TreeNode;
- char *Letters;//字母
- int *Weights;//权值(字母使用的个数)
- int LetterNum;//字母个数
- TreeNode *Tree;//编码树节点集(数组指针)
- int NodeNum;//节点个数
- int CodeLen;//码长
- //统计字母个数
- int CountLetter(char *str)
- {
- int i,k;
- static int Counter[LETTER_NUM];
- LetterNum = 0;
- for(i=0; str[i] != '/0'; i++)
- {
- //如果含有非字母,返回错误
- if(str[i]<0x61 || str[i]>0x7A)
- return 0;
- if(Counter[str[i]-0x61] == 0)
- LetterNum ++;
- Counter[str[i]-0x61] ++;
- }
- //为字母和统计个数分配空间
- Letters = (char*)malloc(LetterNum*sizeof(char));
- Weights = (int*)malloc(LetterNum*sizeof(int));
- for(i=0,k=0; i<LETTER_NUM; i++)
- {
- if(Counter[i] > 0)
- {
- Letters[k] = (char)(i+0x61);
- Weights[k++] = Counter[i];
- }
- }
- return 1;
- }
- //创建编码树
- void CreateTree()
- {
- int i,j;
- int min1,min2,min3;
- NodeNum = LetterNum + LetterNum/2;
- Tree = (TreeNode*)malloc(NodeNum*sizeof(TreeNode));
- for(i=0; i<LetterNum; i++)
- {
- Tree[i].weight = Weights[i];
- Tree[i].parent = -1;
- Tree[i].child0 = -1;
- Tree[i].child1 = -1;
- Tree[i].child2 = -1;
- }
- if(LetterNum % 2 == 0)
- {
- min1 = 0;
- min2 = 1;
- if(Tree[min1].weight > Tree[min2].weight)
- {
- int tmp;
- tmp = min1;
- min1 = min2;
- min2 = tmp;
- }
- for(i=2; i<LetterNum; i++)
- {
- if(Tree[i].weight<Tree[min1].weight)
- {
- min2 = min1;
- min1 = i;
- }
- else if(Tree[i].weight<Tree[min2].weight)
- {
- min2 = i;
- }
- }
- Tree[i].weight = Tree[min1].weight + Tree[min2].weight;
- Tree[i].parent = -1;
- Tree[i].child0 = min1;
- Tree[i].child1 = min2;
- Tree[i].child2 = -1;
- Tree[min1].parent = i;
- Tree[min2].parent = i;
- i++;
- }
- //此处从最新生成的树开始搜索最小树根的树,树高比较大
- /*
- for(; i<NodeNum; i++)
- {
- j = i-1;
- while(Tree[j].parent != -1) j--;
- min1 = j--;
- while(Tree[j].parent != -1) j--;
- min2 = j--;
- while(Tree[j].parent != -1) j--;
- min3 = j--;
- if(Tree[min1].weight > Tree[min2].weight)
- {
- int tmp;
- tmp = min1;
- min1 = min2;
- min2 = tmp;
- }
- if(Tree[min1].weight > Tree[min3].weight)
- {
- int tmp;
- tmp = min1;
- min1 = min3;
- min3 = tmp;
- }
- if(Tree[min2].weight > Tree[min3].weight)
- {
- int tmp;
- tmp = min2;
- min2 = min3;
- min3 = tmp;
- }
- for(; j>=0; j--)
- {
- if(Tree[j].parent == -1)
- {
- if(Tree[j].weight < Tree[min1].weight)
- {
- min3 = min2;
- min2 = min1;
- min1 = j;
- }
- else if(Tree[j].weight < Tree[min2].weight)
- {
- min3 = min2;
- min2 = j;
- }
- else if(Tree[j].weight < Tree[min3].weight)
- {
- min3 = j;
- }
- }
- }*/
- for(; i<NodeNum; i++)
- {
- j = 0;
- while(Tree[j].parent != -1) j++;
- min1 = j++;
- while(Tree[j].parent != -1) j++;
- min2 = j++;
- while(Tree[j].parent != -1) j++;
- min3 = j++;
- if(Tree[min1].weight > Tree[min2].weight)
- {
- int tmp;
- tmp = min1;
- min1 = min2;
- min2 = tmp;
- }
- if(Tree[min1].weight > Tree[min3].weight)
- {
- int tmp;
- tmp = min1;
- min1 = min3;
- min3 = tmp;
- }
- if(Tree[min2].weight > Tree[min3].weight)
- {
- int tmp;
- tmp = min2;
- min2 = min3;
- min3 = tmp;
- }
- for(; j<=i-1; j++)
- {
- if(Tree[j].parent == -1)
- {
- if(Tree[j].weight < Tree[min1].weight)
- {
- min3 = min2;
- min2 = min1;
- min1 = j;
- }
- else if(Tree[j].weight < Tree[min2].weight)
- {
- min3 = min2;
- min2 = j;
- }
- else if(Tree[j].weight < Tree[min3].weight)
- {
- min3 = j;
- }
- }
- }
- Tree[i].weight = Tree[min1].weight + Tree[min2].weight + Tree[min3].weight;
- Tree[i].child0 = min1;
- Tree[i].child1 = min2;
- Tree[i].child2 = min3;
- Tree[i].parent = -1;
- Tree[min1].parent = i;
- Tree[min2].parent = i;
- Tree[min3].parent = i;
- }
- }
- //释放空间
- void DestroyTree()
- {
- if(Letters)
- free(Letters);
- if(Weights)
- free(Weights);
- if(Tree)
- free(Tree);
- }
- //打印生成树
- void PrintTree()
- {
- int i;
- printf("/n----CodeTree----/n");
- for(i=0; i<NodeNum; i++)
- {
- printf("%4d",Tree[i].weight);
- printf("%4d",Tree[i].parent);
- printf("%4d",Tree[i].child0);
- printf("%4d",Tree[i].child1);
- printf("%4d/n/n",Tree[i].child2);
- }
- }
- //显示字母编码表
- void EncodeLetters()
- {
- int i,j,k,t;
- char *code;
- char tmp;
- printf("/n其对应的编码表为:/n");
- code = (char*)malloc(LetterNum*sizeof(char));
- for(t=0; t<LetterNum; t++)
- {
- j = i = t; k = 0;
- while(Tree[j].parent != -1)
- {
- j = Tree[j].parent;
- if(Tree[j].child0 == i)
- code[k++] = '0';
- else if(Tree[j].child1 == i)
- code[k++] = '1';
- else code[k++] = '2';
- i = j;
- }
- code[k] = '/0';//结束符
- for(i=0; i<k/2; i++)//头尾置换
- {
- tmp = code[i];
- code[i] = code[k-i-1];
- code[k-i-1] = tmp;
- }
- printf("%c : %s/n",Letters[t],code);
- }
- free(code);
- }
- //编码
- void Encode(char *lets)
- {
- int i,j,k,t;
- char *code;
- char tmp;
- code = (char*)malloc(LetterNum*sizeof(char));
- CodeLen = 0;
- for(t = 0; lets[t] != '/0'; t++)
- {
- for(i=0; i<LetterNum; i++)
- {
- if(Letters[i] == lets[t])
- break;
- }
- j = i; k = 0;
- while(Tree[j].parent != -1)
- {
- j = Tree[j].parent;
- if(Tree[j].child0 == i)
- code[k++] = '0';
- else if(Tree[j].child1 == i)
- code[k++] = '1';
- else code[k++] = '2';
- i = j;
- CodeLen++;
- }
- code[k] = '/0';//结束符
- for(i=0; i<k/2; i++)//头尾置换
- {
- tmp = code[i];
- code[i] = code[k-i-1];
- code[k-i-1] = tmp;
- }
- printf(code);
- }
- free(code);
- printf("/n");
- }
- //译码
- void Decode(char *codes)
- {
- int i,j,k=0;
- int ch;
- do
- {
- i = NodeNum-1;
- while(Tree[i].child0 != -1 && Tree[i].child1 != -1)
- {
- ch = codes[k++];
- if(ch == '/0')
- break;
- if(ch == '0')
- j = Tree[i].child0;
- else if(ch == '1')
- j = Tree[i].child1;
- else j = Tree[i].child2;
- i = j;
- }
- //写入Decode
- printf("%c",Letters[i]);
- }while(ch != '/0');
- printf("/n");
- }
- //main
- void main()
- {
- char str[100];
- char code[100];
- printf("请输入要编码的字母串(长度小于100):/n");
- scanf("%s",str);
- if(!CountLetter(str))
- {
- printf("The string has error!/n");
- return ;
- }
- CreateTree();
- // PrintTree();
- EncodeLetters();
- printf("对应的编码为:");
- Encode(str);
- printf("总码长为: %d/n", CodeLen);
- printf("根据该编码,给出编码:");
- scanf("%s",code);
- printf("则输出字串:");
- Decode(code);
- }
练习46
最新推荐文章于 2022-12-27 19:02:45 发布