/*********************************************************************************
46. 设有一个字符串,长度小于 100,且全部以英文字母组成。对字串中的每个字
母可用 0,1,2 三个数字进行编码,且数字可以重复使用。
程序要求:(1) 输入字符串,并能判断输入是否有错;
(2) 输出对应的编码表及码长,要求字串的编码总长度为最短;
(3) 根据上述编码表,给出一些编码,然后求出其原字符串。
例如:输入的字符为:ABCBAAADDEF
其对应的编码表为:
A: 2 B: 10
C: 11 D: 12
E: 00 F: O1
对应的编码为:210111022212120001 总码长为:18
根据该编码,给出编码:010001121110222 则输出字串:FEFDCBAAAA.
********************************************************************************/
#include <iostream.h>
#include <string.h>
typedef struct
{
int w;
char let;
int parent;
int child[3];
}TreeNode;
typedef struct
{
TreeNode* pNode;
int root;
}Tree;
#define MaxBit 26
typedef struct
{
char bit[MaxBit];
int start;
} CodeBit;
Tree tree;
CodeBit cb[MaxBit];
void Build2BTree(int n,int count[],char letters[])
{
int i,s,t;
//初始化节点树
tree.pNode = new TreeNode[2*n-1];
t=2*n-1;
for(i=0; i<n; i++)
{
tree.pNode[i].w = count[i];
tree.pNode[i].let = letters[i];
tree.pNode[i].parent = -1;
tree.pNode[i].child[0] = -1;
tree.pNode[i].child[1] = -1;
tree.pNode[i].child[2] = -1;
}
while(i<t)
{
int min1,min2;
min1 = -1; min2 = -1;
//找出权值最小的树
for(s=0; s<i; s++)
{
if(tree.pNode[s].parent == -1)
{
if(min1 == -1)
min1 = s;
else
if(tree.pNode[s].w < tree.pNode[min1].w)
min1 = s;
}
}
//找出权值次小的树
for(s=0; s<i; s++)
{
if(tree.pNode[s].parent == -1 && s != min1)
{
if(min2 == -1)
min2 = s;
else
if(tree.pNode[s].w < tree.pNode[min2].w)
min2 = s;
}
}
//生成新的树
tree.pNode[i].w = tree.pNode[min1].w + tree.pNode[min2].w;
tree.pNode[i].let = '\0';
tree.pNode[i].parent = -1;
tree.pNode[i].child[0] = min1;
tree.pNode[i].child[1] = min2;
tree.pNode[i].child[2] = -1;
tree.pNode[min1].parent = i;
tree.pNode[min2].parent = i;
i++;
}
tree.root = t-1;
}
//返回树的节点类型
int NodeType(int i)
{
if(i == -1)//非节点
return 2;
if(tree.pNode[i].child[0] == -1)//叶子节点
return 1;
return 0;//非叶子节点
}
void Convert3BTree(Tree& tree,int n)
{
int s,t,cur;
//引入循环队列
int* q = new int[n];
s = t = 0;
//树根入列
if(NodeType(tree.root) == 0)
{
q[t] = tree.root;
t = (t+1)%n;
}
//遍历队列
while(s!=t)
{
int select = -1;
int child0,child1;
cur = q[s];
s = (s+1)%n;
child0 = tree.pNode[cur].child[0];
child1 = tree.pNode[cur].child[1];
if(NodeType(child0) == 0)
select = child0;
if(NodeType(child1) == 0)
{
if(select == -1)
select = child1;
else
{
if(tree.pNode[select].w < tree.pNode[child1].w)
select = child1;
}
}
if(select != -1)
{
int c0,c1,p;
c0 = tree.pNode[select].child[0];
c1 = tree.pNode[select].child[1];
p = tree.pNode[select].parent;
tree.pNode[c0].parent = p;
tree.pNode[c1].parent = p;
tree.pNode[p].child[2] = c1;
if(select == child0)
tree.pNode[p].child[0] = c0;
else tree.pNode[p].child[1] = c0;
}
//将类型为非叶子节点的子节点加入队列
if(NodeType(tree.pNode[cur].child[0]) == 0)
{
q[t] = tree.pNode[cur].child[0];
t = (t+1)%n;
}
if(NodeType(tree.pNode[cur].child[1]) == 0)
{
q[t] = tree.pNode[cur].child[1];
t = (t+1)%n;
}
if(NodeType(tree.pNode[cur].child[2]) == 0)
{
q[t] = tree.pNode[cur].child[2];
t = (t+1)%n;
}
}
delete []q;
}
void CodeLetter(Tree& tree,int n)
{
for(int i=0; i<n; i++)
{
int c = i;
int p = tree.pNode[c].parent;
char let = tree.pNode[c].let;
int idx = (int)(let-0x41);
cb[idx].bit[MaxBit-1] = '\0';
cb[idx].start = MaxBit-1;
while(p!=-1)
{
if(tree.pNode[p].child[2] == c)
cb[idx].bit[--(cb[idx].start)] = '2';
else if(tree.pNode[p].child[1] == c)
cb[idx].bit[--(cb[idx].start)] = '1';
else if(tree.pNode[p].child[0] == c)
cb[idx].bit[--(cb[idx].start)] = '0';
c=p;
p = tree.pNode[p].parent;
}
}
}
void Code(char *str,char *code)
{
int i;
for(i=0; str[i]!='\0'; i++)
{
int idx;
idx = str[i]-0x41;
strcat(code,cb[idx].bit+cb[idx].start);
}
}
void Decode(char *code,char *str)
{
int i = 0;
int j = 0;
while(code[i]!='\0')
{
int p = tree.root;
while(NodeType(p) == 0)
{
p = tree.pNode[p].child[code[i]-0x30];
i++;
}
str[j++] = tree.pNode[p].let;
}
str[j] = '\0';
}
void ShowLetterCode(int n,char letters[])
{
int i;
for(i=0; i<n; i++)
{
int idx = (int)(letters[i]-0x41);
cout<<letters[i]<<": "<<cb[idx].bit+cb[idx].start<<endl;
}
}
void FreeTreeNode()
{
delete []tree.pNode;
}
void main()
{
char str[101] = {'\0'};
char code[500] = {'\0'};
int i,n;
int count[26]={0};
char letters[26];
//输入编码字符串
cout<<"请输入字符串(全部以英文字母组成):"<<endl;
cin>>str;
//排错和统计字符出现频率
for(i=0; str[i]!='\0'; i++)
{
if(str[i]<0x41 ||
(str[i]>=0x5B && str[i]<=0x60) || str[i]>=0x7B)
{
cout<<"输入有误:请输入英文字母!"<<endl;
return;
}
else if(str[i]>0x60)
{
str[i] = str[i] - 0x20;
}
count[str[i]-0x41]++;
}
for(i=0,n=0; i<26; i++)
{
if(count[i]>0)
{
count[n] = count[i];
letters[n] = (char)(i+0x41);
n++;
}
}
//输出字母的出现频率
for(i=0; i<n; i++)
cout<<letters[i]<<":"<<count[i]<<" ";
cout<<endl;
cout<<"输入的字符为:"<<endl<<str<<endl;
//建立最小权二叉树
Build2BTree(n,count,letters);
//转换为权值最小的三叉树
Convert3BTree(tree,n);
//显示字母对应的编码
CodeLetter(tree,n);
ShowLetterCode(n,letters);
//编码
Code(str,code);
cout<<"字符串对应编码为:"<<code<<" 总码长为:"<<strlen(code)<<endl;
//译码
cout<<"请输入代码:";
cin>>code;
cout<<"译码为:";
Decode(code,str);
cout<<str<<endl;
FreeTreeNode();
}练习46
最新推荐文章于 2024-04-28 08:18:33 发布

4993

被折叠的 条评论
为什么被折叠?



