练习46

/*********************************************************************************

  
 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();
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值