zoukankan      html  css  js  c++  java
  • 编码节点poj 1521 Entropy huffman(哈夫曼)编码

    新手发帖,很多方面都是刚入门,有错误的地方请大家见谅,欢迎批评指正

        题目链接:http://poj.org/problem?id=1521

        题目很长,长的都读不懂咋回事,不过很好懂得,意思就是给你个字符串,让你输出用普通ASCII编码和用huffman编码分别占用的位数,然后输出压缩比;

        第一次写哈夫曼编码,写了半天,到最后还wa了好几次,这个压缩比的输出格式太蛋疼了,他说保存一名小数,但是如果是x.0,则直接输出x,这一天找了半天,最后试了好些格式才给试出来的。虽然题目没有要求写编码和解码,但是由于想练习下,我自己也给写了出来;

        

        大题思路是:首先找出每一个字符出现的频率(即次数),然后每一个字符首先占一个节点,然后对全部节点取频率最小的两个,再结构一个节点为这两个节点的父节点,其频率为这个节点频率之和,直到只剩下一个节点,此节点即为根节点,然后对各个节点进行编码,跟节点没有编码,然后递归编码,规则为:一个节点的左孩子的编码为此节点的编码加‘0’,右孩子的编码为此节点的编码+‘1’;直到没有左右孩子为止;

        

        然后求编码长度的时候,对于全部的叶子节点,让其编码长度乘频率,然后累加,就得到全部编码的长度了。

        参考代码如下:

        

        每日一道理
    父亲对于儿子来说,是座耸立的高山,而儿子只是颗石子,源于山,却并不了解山。生活中诸多爱的密码,是需用细节来解读的,在亲情的沃土上,要想搞得最美的果实,惟有期待那存在于瞬间的心与心的共鸣,爱与爱的默契。
    #include <iostream>
    #include <iomanip>
    #include <cstdlib>
    #include <cstring>
    #include <queue>
    #include <cmath>
    #include <cstdio>
    using namespace std;
    struct Node
    {
    	int val;   //记载节点的频率
    	char c;    //节点机率的字符,中间节点的c值均设为0;
    	int len;	//编码的长度;
    	char code[31]; //编码;
    	int num;   //记载在数组中的位置,存属为了操纵便利,完全可以没有;
    	int lchild; //左孩子的下标 若没有 为-1;
    	int rchild; //右孩子的下标,若没有,为-1;
    	int parent; //父亲节点的下标,若没有,为-1;
    };
    bool operator <(const Node &a,const Node &b)  //考虑到用到优先队列取最小和次小,全部重载下<号
    {
    	return a.val>b.val;
    }
    Node a[201];
    int lens;    //字符串长度
    int lentree;  //数的节点的个数;
    char s[10001]; //读入的字符串
    int flag[10001];  //用来判断字符串的某一名的字符之前有无出现过
    int pcodelen,nowcodelen;  //分别表现用ASCII编码和用huffman编码的长度
    double ans;     //压缩比
    void codenode(int k)  //对各个节点进行编码;
    {
    	if(a[k].lchild!=-1)
    	{
    		strcpy(a[a[k].lchild].code,a[k].code);
    		a[a[k].lchild].code[a[k].len]='0';
    		a[a[k].lchild].len=a[k].len+1;
    		codenode(a[k].lchild);
    	}
    	if(a[k].rchild!=-1)
    	{
    		strcpy(a[a[k].rchild].code,a[k].code);
    		a[a[k].rchild].code[a[k].len]='1';
    		a[a[k].rchild].len=a[k].len+1;
    		codenode(a[k].rchild);
    	}
    	if(a[k].lchild==-1&&a[k].rchild==-1)
    	{
    		nowcodelen+=a[k].val*a[k].len;  //如果为叶子几点则令nowcodelen的值增加此节点编码长度的值
    	}
    
    }
    void codestr(char *source,char *code) //对字符串进行编码
    {
    	int i;
    	int j;
    	int lencode=0;
    	int lensource=strlen(source);
    	for(i=0;i<lensource;i++)
    	{
    		for(j=0;j<(lentree+1)/2;j++)
    		{
    			if(a[j].c==source[i])
    			{
    				strcpy(code+lencode,a[j].code);
    				lencode+=a[j].len;
    			}
    		}
    	}
    	code[lencode]=0;
    }
    void decode(char *code,char *str)//解码
    {
    	int i;
    	int lenstr=0;
    	int lencode=strlen(code);
    	for(i=0;i<lencode;)
    	{
    		int t=lentree-1;
    		while(a[t].lchild!=-1||a[t].rchild!=-1)
    		{
    			if(code[i]=='0')
    			{
    				t=a[t].lchild;
    				i++;
    			}
    			else
    			{
    				t=a[t].rchild;
    				i++;
    			}
    		}
    		str[lenstr++]=a[t].c;
    	}
    	str[lenstr]=0;
    }
    void execute()
    {
    	if(lentree==1)
    	{
    		nowcodelen=a[lentree-1].val;
    		return ;
    	}
    	int i;
    	priority_queue<Node> q;
    	while(!q.empty())
    		q.pop();
    	for(i=0;i<lentree;i++)
    	{
    		a[i].rchild=a[i].lchild=-1;
    		a[i].num=i;
    		q.push(a[i]);
    	}
    	while(q.size()!=1)//结构最优二叉树
    	{
    		Node x1=q.top();
    		q.pop();
    		Node x2=q.top();
    		q.pop();
    		a[lentree].val=x1.val+x2.val;
    		a[lentree].rchild=x1.num;
    		a[lentree].lchild=x2.num;
    		a[lentree].num=lentree;
    		q.push(a[lentree]);
    		lentree++;
    	}
    	a[lentree].len=0; //先令根节点的编码长度为0;
    	nowcodelen=0;
    	codenode(lentree-1);
    
    	/*
    	char code[10001];
    	codestr(s,code);
    	cout<<"编码为:"<<endl;
    	cout<<code<<endl;
    	char str[10001];
    	decode(code,str);
    	cout<<"解码后字符串为:"<<endl;
    	cout<<str<<endl;
    	*/
    }
    int main()
    {
    	char c;
    	char cmp[6]={'E','N','D','\0'};
    	while(gets(s)&&strcmp(s,cmp)!=0)
    	{	
    		lens=strlen(s);
    		lentree=0;
    		memset(flag,-1,sizeof(flag));
    		memset(a,0,sizeof(a));
    		for(int i=0;i<lens;i++)//结构全部叶子节点
    		{
    			if(flag[i]!=-1)
    				a[flag[i]].val++;
    			else
    			{
    				a[lentree].c=s[i];
    				a[lentree].val++;
    				for(int j=i+1;j<lens;j++)
    					if(s[j]==s[i])
    						flag[j]=lentree;
    				
    				lentree++;
    			}
    		}
    		pcodelen=8*lens; //ASCII编码长度就为字符串长度乘8
    		execute();
    		ans=(double)pcodelen/(double)nowcodelen; 
    		cout<<pcodelen<<' ';
    		cout<<nowcodelen<<' ';
    		if((ans-floor(ans))<0.1) //如果ans小数点后一名为0,则输出个整数
    			cout<<ans<<endl;
    		else
    			cout<<fixed<<setprecision(1)<<ans<<endl;
    	}
    	return 0;
    }

    文章结束给大家分享下程序员的一些笑话语录: 女人篇
      有的女人就是Windows虽然很优秀,但是安全隐患太大。
      有的女人就是MFC她条件很好,然而不是谁都能玩的起。
      有的女人就是C#长的很漂亮,但是家务活不行。
      有的女人就是C++,她会默默的为你做很多的事情。
      有的女人就是汇编虽然很麻烦,但是有的时候还得求它。
      有的女人就是SQL,她会为你的发展带来莫大的帮助。

    --------------------------------- 原创文章 By
    编码和节点
    ---------------------------------

  • 相关阅读:
    Go 语言打包静态文件
    Go 语言编写单元测试
    从开源项目看 Python 单元测试
    从开源项目看python代码注释
    Celery 源码解析八:State 和 Result
    Celery 源码解析七:Worker 之间的交互
    Celery 源码解析六:Events 的实现
    Celery 源码解析五: 远程控制管理
    Celery 源码解析四: 定时任务的实现
    覆盖equals时请遵守通用约定
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/3112992.html
Copyright © 2011-2022 走看看