数据结构课程设计第三题程序内容

题目:

在一个加密应用中,要处理的信息来自下面的字符集,各个字符的相关使用频度如下:

字符空格 A  B  C  D   E F  G  H  I   J  K  L M
频度 180 64 13 23 32103 22 15   47 57  1 5 31  20
字符 N O P   Q  R  S T  U  V  W X Y Z
频度 55 63 15 1 48  56  80 25 7 18  2  16  1

现请编写程序你实现如下功能:

1)运行时,由用户输入来初始化字符集大小和相应用字符。

2)输入一个要加密的字符串,将其加密。

3)输出解密字符串。


分析过程略,具体程序如下:

#include <iostream>
using namespace std;
#define MAX_FILE 5000//假设的文件最大长度
#define MAXLIST 256//最大MAP值
#define MAX_HOFFMAN_LENGTH 50//哈夫曼编码长度
char dictionary[MAXLIST][2]={0};//Hash映射,[][0]为权值,[][1]为字符
char fileContent[MAX_FILE];//处理的字符串大小
int Hoffman[MAXLIST][MAX_HOFFMAN_LENGTH]={2};//哈夫曼编码序列
char HoffmanList[MAXLIST]={0};//哈夫曼编码对应的字符有序序列
char HoffFileCode[MAX_FILE]={0};//哈夫曼编码字符串序列
char HoffFile[MAX_FILE]={0};
//编码到假设的文件的哈夫曼压缩格式: 依次存储 原字符串长度(1字节存储:可扩展到2字节)、哈夫曼编码数(1字节)、每个哈夫曼编码的长度序列、每个哈夫曼编码对应的字符序列、编码过的哈夫曼字符串
char GetFile[MAX_FILE]={0};//解码序列
void ShellSort(char pData[MAXLIST][2],int Count)//Shell排序,用于准备有序化要构造的编码权值构造哈夫曼树做准备
{
	int step[4]={9,5,3,1};//增量序列
	int iTemp,cTemp;
	int k,s,w;
	for(int i=0;i<4;i++)
		{
		  k=step[i];
		  s=-k;
		  for(int j=k;j<Count;j++)
		  {
			  iTemp=pData[j][0];
		      cTemp=pData[j][1];
		      w=j-k;
			  if(s==0)
			  {
				  s=-k;
				  s++;
				  pData[s][0]=iTemp;
				  pData[s][1]=cTemp;
			  }
			  while((iTemp<pData[w][0])&&(w>=0)&&(w<=Count))
			  {
				  pData[w+k][0]=pData[w][0];//权值交换
				  pData[w+k][1]=pData[w][1];//字符交换
				  w=w-k;
			  }
			  pData[w+k][0]=iTemp;
			  pData[w+k][1]=cTemp;
		  }
		}
}
struct TNode//哈夫曼树结点
{
	 TNode* pNode;
	 TNode* lNode;
	 TNode* rNode;
	 char dictionary;
	 char weight; 
	 TNode(char dic,char wei)
	 {
		 pNode=0;
		 lNode=0;
		 rNode=0;
		 dictionary=dic;
		 weight=wei;
	 }
};
struct LNode//链表结点,用于存储哈夫曼树结点,进而构造哈夫曼树(保证每一步链表结点包含的哈夫曼结点都是有序的)
{
	 LNode* prev;
	 LNode* next;
	 TNode* tnode;
	 LNode()
	 {
		  prev=next=0;
		  tnode=0;
	 }
};
int len=0;//哈夫曼编码数
int deep=-1;//深度
void Preorder(TNode * p);//前序遍历
void byLeft(TNode*p)//经由左结点
{
	 deep++;
	 Hoffman[len][deep]=0;
	 Preorder(p);
	 Hoffman[len][deep]=2;
	 deep--;
}
void byRight(TNode*p)//经由右结点
{
	deep++;
	Hoffman[len][deep]=1;
	Preorder(p);
	Hoffman[len][deep]=2;
	deep--;
}
void Preorder(TNode * p)
{
	 if(p->lNode!=0)//当左子结点非空则遍历
	 {
		  byLeft(p->lNode);
	 }
     if(p->rNode!=0)//当右子结点非空则遍历
	 {
          byRight(p->rNode);
	 }
	 if((p->lNode==0)&&(p->rNode==0))//当左右结点都为空,则增加哈夫曼编码数到另一个记录
	 {
		  Hoffman[len][deep+1]=2;
		  int i=0;
		  for(;Hoffman[len][i]!=2;i++)
		  {
			  Hoffman[len+1][i]=Hoffman[len][i];
		  }
		  Hoffman[len+1][i]=2;
		  HoffmanList[len]=p->dictionary;
		  len++;
	 }
}
char generateOne(int k)//产生k个连续1的二进制串,比如111,1111,111111,用于编码进假设的文件
{
	 char c=0;
	 for(;k!=0;k--)
	 {
		  c|=(1<<(k-1));
	 }
	 return c;
}
int compareBits(char b1,char b2,char c,int l,int d)//判断由 [b1,b2]  组成的16位二进制数以d为起点,是否是长度为l的c二进制串(哈夫曼编码)的前缀
{
	unsigned __int8 t=(((((0x00ff&b1)<<8)|(0x00ff&b2))>>(8-d))&0x00ff);
	return (((t)&((generateOne(l)<<(8-l))&0xff))==((c<<(8-l))&0xff));
}
int main()
{
   /*  或许假定的文件字符串向量中的字符串 */
	cout<<"请输入要压缩的字符串:";
    cin>>fileContent;
    cin.get();
	unsigned short fileLen=0;
   /*  Hash进dictionary */
	for(int i=0;fileContent[i]!='\0';i++,fileLen++)
	{
		++dictionary[fileContent[i]][0];
		dictionary[fileContent[i]][1]=fileContent[i];
	}
	int len=0;
   /*  把Hash了的dictionary向前靠拢 */
	{
		for(int i=0;i!=MAXLIST;i++)
		{
			 if(dictionary[i][0]!=0)
			 {
				 dictionary[len][0]=dictionary[i][0];
				 dictionary[len][1]=dictionary[i][1];
				 len++;
			 }
		}
	}
	cout<<"哈夫曼编码个数:"<<len<<endl;
   /*  对dictionary按权值进行排序 */
	ShellSort(dictionary,len);
   /* 构造链表,链表中放有序dictionary权值的树结点 */
	LNode* head=new LNode,*p=head;
	head->next=new LNode;
	TNode *tempTNode=new TNode(dictionary[0][1],dictionary[0][0]);
	head->tnode=tempTNode;
	{
		for(int i=0;i!=len-1;i++)
		{
			p->next->prev=p->next;
			p=p->next;
			p->next=new LNode;
			tempTNode=new TNode(dictionary[i+1][1],dictionary[i+1][0]);
			p->tnode=tempTNode;
		}
	}
	delete p->next;
	p->next=0;
   /* 每次最小权值的前面两个链表结点中的树结点组成一个子树,子树有合权值,子数的根按权值排序进链表*/
	for(p=head;p->next!=0;)
	{
		p->tnode->pNode=new TNode('\0',(p->tnode->weight)+(p->next->tnode->weight));
		p->next->tnode->pNode=p->tnode->pNode;
		p->tnode->pNode->lNode=p->tnode;
		p->tnode->pNode->rNode=p->next->tnode;
		head=p->next;
		delete p;
		p=head;
		p->tnode=p->tnode->pNode;
		for(LNode* t=head;t->next!=0;t=t->next)
		{
			if(t->tnode->weight>t->next->tnode->weight)
			{
				TNode* k=t->tnode;
				t->tnode=t->next->tnode;
				t->next->tnode=k;
			}
		}
	}
	int code[500],h=0;
   /* 前序遍历构造哈夫曼编码 */
	Preorder(p->tnode);
	{
		for(int i=0;i!=len;i++)
			dictionary[HoffmanList[i]][0]=i;
	}
   /* 存储字符串的哈夫曼压缩编码串,并且打包文件格式 */
	int codeLen=0,total=0;
	{
		for(int i=0;i!=fileLen;i++)
		{
			int j=dictionary[fileContent[i]][0];
			for(int k=0;Hoffman[j][k]!=2;k++)
			{
				HoffFileCode[codeLen]|=(Hoffman[j][k]<<(7-total%8));
				code[h++]=Hoffman[j][k];
				if(((total+1)%8)==0)
				{
					HoffFile[1+len*3+1+codeLen]=HoffFileCode[codeLen];
					codeLen++;
				}
				total++;
			}
		}
	}
	HoffFile[1+len*3+1+codeLen]=HoffFileCode[codeLen];
	HoffFile[0]=(fileLen);
   /* 解压缩假定的文件HoffFile成为原字符串序列 */
	cout<<"哈夫曼编码序列:\n";
	HoffFile[1]=len;
	{
		for(int i=0,j=0;i!=len;i++,j=0)
		{
			for(;Hoffman[i][j]!=2;j++);
			HoffFile[i+2]=j;
			HoffFile[i+2+2*len]=HoffmanList[i];
			for(int k=0;k!=j;k++)
			{
				cout<<Hoffman[i][k];
				HoffFile[i+2+len]|=(Hoffman[i][k]<<(j-1-k));
			}
			cout<<":"<<HoffmanList[i]<<endl;
		}

	}
    {
		for(int i=0,j=0;i!=(HoffFile[0]&0xff);i++)
		{
			for(int k=0;k!=HoffFile[1];k++)
			{
				char l=HoffFile[2+k],d=j%8,b1=HoffFile[j/8+2+HoffFile[1]*3],b2=HoffFile[j/8+1+2+HoffFile[1]*3];
				char c=HoffFile[HoffFile[1]+2+k];
				if(compareBits(b1,b2,c,l,d))
				{
					j+=HoffFile[2+k];
					GetFile[i]=HoffFile[2+HoffFile[1]*2+k];
					break;
				}
			}
		}
	}
		{
		cout<<"哈夫曼压缩打包假定文件格式二进制的文本体现:";
		
		for(int i=0;i!=HoffFile[0]+HoffFile[1]*3;i++)
		{
			cout<<HoffFile[i];
		}
		cout<<endl;
	}
	{
		cout<<"哈夫曼压缩后二进制序列:";
        for(int i=0;i!=h;i++)
		{
			cout<<code[i];
			if((i+1)%8==0)
			cout<<" ";
		}
	}
	cout<<endl;
	cout<<"原字节数为:"<<fileLen<<endl;
	cout<<"压缩后字节数为:"<<(h)/8+1<<endl;
	cout<<"压缩率为"<<((h/8.0+1)/fileLen)*100<<"%"<<endl;
	{
		cout<<"字符串字节数为:"<<(HoffFile[0]&0xff)<<endl;
		cout<<"字符串解压序列为:";
		for(int i=0;i!=(HoffFile[0]&0xff);i++)
		{
			cout<<GetFile[i];
		}
		cout<<endl;
		cin.get();
	}
	return 1;
}




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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值