哈夫曼编码

题目要求:

根据哈夫曼编码的原理,编写一个程序,在用户输入结点权值的基础上求赫夫曼编码,并能把给定的编码进行译码。

(1)初始化:从键盘输入一字符串(或读入一文件),统计出现的字符和每个字符出现的频率,将字符出现的频率作为结点的权值,建立哈夫曼树。对各个字符进行哈夫曼编码,最后打印输出字符及每个字符对应的哈夫曼编码。

(2)编码:利用已建好的哈夫曼树对“输入串”进行哈夫曼编码,最后打印输入串对应的哈夫曼编码(写入文件)。

(3)译码:利用已建好的哈夫曼树对给定的一串代码进行译码,并打印输出得到的字符串。(选作)

测试数据:对字符串{casbcatbsatbat}进行编码;对电文“1101000”译码。字符集D={   ?},出现频率为w={?}

思路:

用c++的类来完成,对于输入的字符串,我们要知道树中每个字符出现的频率,还有每个字符对应的编码,这中一一对应关系,我们用map完成。我们还需要记录哈夫曼树的根,便于对电文译码。

对于二叉树的构建,我们不用数组,就用二叉链表解决,每个节点对应的成员为字符、频率、左右孩子。

节点类:

//节点类 
class HuffmanNode{
	public:
		char date;
		int freq;
		HuffmanNode *left;
		HuffmanNode *right;
		HuffmanNode(char date,int freq)
		{
			this->date=date;
			this->freq=freq;
			left=right=NULL;
		}
};

哈夫曼树的数据成员

private:
		map freq;      //字符--对应频次 
		map codes;  //字符--对应编码 
		HuffmanNode *root;

步骤一、构建哈夫曼树(用类的构造函数)。

先统计字符的种类和每种字符出现个数,随后以每一种字符构建一个节点,作为哈夫曼树的叶子,随后将这些节点都放进一个数据结构L中,当L中还有一个以上的节点时,找出权值(也就是频率)最小的A,和次最小的B。A,B的权值相加构成一个新节点C,C的左孩子为A,右孩子为B。随后C进入L,A、B从L中出来。当L中只剩下一个节点时,剩下的那个就是哈夫曼树的根。

现在的难点就是找出这么一种数据结构L,能随时拿出两个数据或加入一个数据,而且每次拿出的两个数据要是权值最小的,也就是权值最小的优先拿出。

课本上用线性表完成,利用叶子节点和二度节点的数量关系创建一个数组,每次找数组中没有父亲的权值最小的节点最小,这个找的过程很麻烦。

既然是权值最小的优先拿出,而c++stl库就有一种数据结构,能按照自己设定的优先级来处理对象---优先队列。我们只需要将权值小的放在堆顶,每次拿出堆顶的两个出来就行,就避免了找的这个过程。

Huffman(string s)
		{//用构造函数来构造一颗哈夫曼数 
			//创建  字符---出现次数  的键值对 
			for(int i=0;i,Compare> pq;
			for(auto it:freq)
			{
//				HuffmanNode *p=new HuffmanNode(it.first,it.second);
				pq.push(new HuffmanNode(it.first,it.second));
			}
			//开始,合并最小的两个,出队,合并结果入队的循环操作,直到队里只剩下一个。
			while(pq.size()>1)
			{
				//最小值为左儿子,次小值为右儿子 
				HuffmanNode* left=pq.top();
				pq.pop();
				HuffmanNode* right=pq.top();
				pq.pop();
				
				HuffmanNode* parent=new HuffmanNode('#',left->freq+right->freq);
				parent->left=left;
				parent->right=right;
				pq.push(parent);
			}
			root=pq.top();//最后剩下根 
			getcodes(root,"");
		}
		//求出每个叶子对应的01编码 
		void getcodes(HuffmanNode* root,string s)
		{
			if(root==NULL)
			{
				return ;
			}
			if(root->date!='#')
			{
				codes[root->date]=s;
			}
			//往左走 
			getcodes(root->left,s+'0');
			getcodes(root->right,s+'1');
		}

步骤二、求出每个叶子的01编码

在步骤一里

步骤三、利用已经键好的哈夫曼树,对输入串解码或对01串译码

//刚开始输入串对应的哈夫曼编码 
		string getEncodedText(string s)
		{
			string Encodedtext="";
			for(auto i:s)
			{
				Encodedtext+=codes[i];
			}
			return Encodedtext;
		}
		
		//构建好哈夫曼树后,任意输入一个有效串(串中每个字符在哈夫曼树的叶子中能找到),输出01编码
		string str_to_01(string s)
		{
			string codeed="";
			for(int i=0;ileft;
				else
				    cur=cur->right;
				if(cur==NULL)
				{
					cout<<"你输入的01编码无法翻译!!!!!\n";
					return "######";
				}
				if(cur->date!='#')
				{
					ans+=cur->date;
					cur=root;
				}
			}
			if(cur!=root) cout<<"所给的01编码不完整,但是能翻译。\n";
			return ans;
		}

完整代码:

#include
#include
#include
#include
#include
using namespace std;
//节点类 
class HuffmanNode{
	public:
		char date;
		int freq;
		HuffmanNode *left;
		HuffmanNode *right;
		HuffmanNode(char date,int freq)
		{
			this->date=date;
			this->freq=freq;
			left=right=NULL;
		}
};
//确定优先队列的优先级 
class Compare{
	public:
		bool operator()(HuffmanNode *a,HuffmanNode *b)
		{
			return a->freq > b->freq;
		}
};

class Huffman{
	public:
		Huffman(string s)
		{//用构造函数来构造一颗哈夫曼数 
			//创建  字符---出现次数  的键值对 
			for(int i=0;i,Compare> pq;
			for(auto it:freq)
			{
//				HuffmanNode *p=new HuffmanNode(it.first,it.second);
				pq.push(new HuffmanNode(it.first,it.second));
			}
			//开始,合并最小的两个,出队,合并结果入队的循环操作,直到队里只剩下一个。
			while(pq.size()>1)
			{
				//最小值为左儿子,次小值为右儿子 
				HuffmanNode* left=pq.top();
				pq.pop();
				HuffmanNode* right=pq.top();
				pq.pop();
				
				HuffmanNode* parent=new HuffmanNode('#',left->freq+right->freq);
				parent->left=left;
				parent->right=right;
				pq.push(parent);
			}
			root=pq.top();//最后剩下根 
			getcodes(root,"");
		}
		//求出每个叶子对应的01编码 
		void getcodes(HuffmanNode* root,string s)
		{
			if(root==NULL)
			{
				return ;
			}
			if(root->date!='#')
			{
				codes[root->date]=s;
			}
			//往左走 
			getcodes(root->left,s+'0');
			getcodes(root->right,s+'1');
		}
		
		//刚开始输入串对应的哈夫曼编码 
		string getEncodedText(string s)
		{
			string Encodedtext="";
			for(auto i:s)
			{
				Encodedtext+=codes[i];
			}
			return Encodedtext;
		}
		
		//构建好哈夫曼树后,任意输入一个有效串(串中每个字符在哈夫曼树的叶子中能找到),输出01编码
		string str_to_01(string s)
		{
			string codeed="";
			for(int i=0;ileft;
				else
				    cur=cur->right;
				if(cur==NULL)
				{
					cout<<"你输入的01编码无法翻译!!!!!\n";
					return "######";
				}
				if(cur->date!='#')
				{
					ans+=cur->date;
					cur=root;
				}
			}
			if(cur!=root) cout<<"所给的01编码不完整,但是能翻译。\n";
			return ans;
		}
		void showfreq()
		{
			cout<<"字符--对应频率\n";
			for(auto i:freq)
			{
				cout< freq;      //字符--对应频次 
		map codes;  //字符--对应编码 
		HuffmanNode *root;
};
int main()
{
	string s="casbcatbsatbat";
	string _01code="1101000";
	Huffman h(s);
    
    cout<

运行:

哈夫曼编码_第1张图片

你可能感兴趣的:(数据结构学习记录,算法)