贪心算法-赫夫曼编码

      赫夫曼编码主要用于数据文件的压缩,用满二叉树实现的,字符都位于树叶上。赫夫曼算法:在输入的字符结点中,选择出现频率最小的2个结点,合并两个结点,形成新的树。新树频率为2个结点的频率之和。在新结点和原始结点(除去合并的2个结点)再寻找出现频率最小的个结点合并。依次下去,直到所有结点都合并在一个树上,此时生成的树为赫夫曼编码树。

a(10)  e(15)    i(12)    s(3)     t(4)      p(13)     n(1)   (待编码的字符信息,后面括号中是该字符出现的频率)

n(1)    s(3)      t(4)      a(10)    i(12)    p(13)    e(15)    (程序中的insert,将其插入到list中,按出现的频率由小到大排序)

n(1)   s(3),    t(4)     T1(4)    a(10)   i(12)     p(13)     e(15) (选取出现频率最小的2个结点n、s合并成新树T1,将T1按出现频率大小插入到list中,T1的左儿子为n,右儿子s)

n(1)    s(3),     t(4)     T1(4),    T2(8)   a(10)     i(12)     p(13)     e(15)    (选取出现频率最小从t开始,T2左儿子为t,右儿子为T1)

n(1)    s(3),     t(4)     T1(4),    T2(8)   a(10),     i(12)     p(13)     e(15)    T3(18)   (选取出现频率最小从T2开始,T3左儿子T2,右儿子a)

n(1)    s(3),     t(4)     T1(4),    T2(8)   a(10),     i(12)     p(13),     e(15)    T3(18)     T4(25)     (选取出现频率最小从i开始,T4左儿子i,右儿子p)

n(1)    s(3),     t(4)     T1(4),    T2(8)   a(10),     i(12)     p(13),     e(15)    T3(18),     T4(25)   T5(33)  (选取出现频率最小从e开始,T5左儿子e,右儿子T3)

n(1)    s(3),     t(4)     T1(4),    T2(8)   a(10),     i(12)     p(13),     e(15)    T3(18),     T4(25)   T5(33),    T6(58)   (选取出现频率最小从T4开始,T6左儿子T4,右儿子T5) 

完成赫夫曼树的生成,如下图:

                                                                   

编码采用向左为0 ,向右为1,各字符对应的赫夫曼编码如下:

                          a:111  ;e:10  ;i:00   ;s:11011   ;t:1100  ;p:01   ;n:11010  。

对于程序中的code()函数如何实现记录赫夫曼码,如n的赫夫曼码获得过程:在生成赫夫曼时,n是T5的后代,而T5是根节点T6的右儿子,根据编规则向右为1,所以T5所有后代(e,t,n,s)的赫夫曼码push  1,因为T5在list中位置为k=11。在编程中判断k奇数,则该处结点的所有后代赫夫曼码push  1,T3、T2、T1对n的赫夫曼码分别是1 ,0,1。所以n赫夫曼码为11010。其实树中所有向右的结点在list中的位置为奇数,向左为偶数。在程序中判断该结点在list 中的位置,决定对其儿子赫夫曼码贡献是0还是1

代码如下:

Huuffman.h

#pragma once
#include<iostream>
#include<list>
#include<vector>
using namespace std;
template<typename Comparable>
struct HuffNode
{
	HuffNode *left;
	HuffNode *right;
	int num;//出现的频率
	Comparable name;//编码的字符串
	vector<int>cod;//该字符的编码
	HuffNode(Comparable n,int nu,HuffNode *l,HuffNode *r):name(n),num(nu),left(l),right(r){}
	HuffNode(int nu,HuffNode *l,HuffNode *r):num(nu),left(l),right(r){}
	HuffNode(HuffNode *l,HuffNode *r):left(l),right(r){}
};
template<typename Comparable>
class Huffmancode
{
public:
	void insert(Comparable name,int num);//将输入的字符插入vector中
	void huffcode();//进行赫夫曼编码
	void code(HuffNode<Comparable> *&t,int k);
	void findcode(Comparable x);//查找某元素的赫夫曼码
	void find(string c);//已知赫夫曼码查找其对应的元素
private:
	list<HuffNode<Comparable> >m_huffman;//保存总的要编码的字符 
	void findc(HuffNode<Comparable> *t,Comparable x);//查找某元素的赫夫曼码
	void findx(HuffNode<Comparable> *t,vector<int>co);
};

Huuffman.cpp

#include "stdafx.h"
#include"Huffman.h"
#include<iostream>
#include<list>
#include<vector>
using namespace std;
template<typename Comparable>
void Huffmancode<Comparable>::insert(Comparable name,int num)
{
	HuffNode<Comparable> huffnode(name,num,NULL,NULL);
	list<HuffNode<Comparable> >::iterator it;
	if(m_huffman.size()==0)
	{
	m_huffman.push_back(huffnode);
	}
	else
	{
		for(it=m_huffman.begin();it!=m_huffman.end();++it)//将待编码的按照出现频率的大小排序,存储在list中
		{
			if(it->num>huffnode.num)
				break;
		}
		m_huffman.insert(it,huffnode);
	}
}
template<typename Comparable>
void Huffmancode<Comparable>::huffcode()//生成赫夫曼树
{
	int k=0;
	list<HuffNode<Comparable> >::iterator it;
	list<HuffNode<Comparable> >::iterator t=m_huffman.begin();
	list<HuffNode<Comparable> >::iterator t2=++t;
	list<HuffNode<Comparable> >::iterator t1=m_huffman.begin();
	while(m_huffman.size()-k>1)
	{
	
		HuffNode<Comparable> huffnode(t1->num+t2->num,&(*t1),&(*t2));
		HuffNode<Comparable>* m1=&(*t1);
		HuffNode<Comparable>* m2=&(*t2);
		code(m1,k);    //进行编码
		code(m2,k+1);  //进行编码
		k=k+2;
		for(it=m_huffman.begin();it!=m_huffman.end();++it)
		{
			 if(it->num>huffnode.num)
			 {
				break;
			 }
		}
		m_huffman.insert(it,huffnode);
		++(++t1);
		++(++t2);
	}
}

template<typename Comparable>
void Huffmancode<Comparable>::code(HuffNode<Comparable> *&t,int k)//编码
{
	if(k%2==0)                             
	{
		if(t!=NULL)
		{
			t->cod.push_back(0);
			code(t->left,k);
			code(t->right,k);
		}
	}
	else
	{
		if(t!=NULL)
		{
			t->cod.push_back(1);
			code(t->left,k);
			code(t->right,k);
		}
	}
}
//查找某个元素的编码
template<typename Comparable>
void Huffmancode<Comparable>::findcode(Comparable x)
{
	list<HuffNode<Comparable> >::iterator it=m_huffman.end();
	--it;
	HuffNode<Comparable> *t=&(*it);  //获取赫夫曼树的根节点的地址,由前面huffcode()函数生成赫夫曼树可知,根节点是存储在list中的最后一个位置
	findc(t,x);
	cout<<endl;
}
template<typename Comparable>
void Huffmancode<Comparable>::findc(HuffNode<Comparable> *t,Comparable x)
{
	if(t!=NULL)
	{
		if(t->name==x)                         //采用遍历树的方法,直到找到name为x的结点,然后把其编码输出
		{
			for(int i=t->cod.size()-1;i>=0;i--)
				cout<<t->cod[i]<<" ";
		}
		findc(t->left,x);  
		findc(t->right,x);
	}
}
//解码,已知某个赫夫曼码找到对应的元素
template<typename Comparable>
void Huffmancode<Comparable>::find(string c)
{
	list<HuffNode<Comparable> >::iterator it=m_huffman.end();
	--it;
	HuffNode<Comparable> *t=&(*it);  //获取赫夫曼树的根节点
	vector<int>co;
	int temp;
	for(int i=c.size()-1;i>=0;i--)//将输入的string类型每一位上转换为int并放在vector中
	{
		temp=(int)c[i]-48;     //1是char类型时,转换为int类型,值为49,需要减48
		co.push_back(temp);
	}
	findx(t,co);     //co中保存的是赫夫曼码
	cout<<endl;
}
template<typename Comparable>
void Huffmancode<Comparable>::findx(HuffNode<Comparable> *t,vector<int>co)
{
	if(t!=NULL)
	{
		if(t->cod==co)            //遍历赫夫曼树,找到赫夫曼码为co的结点,输出对应的元素,完成解码工作
        cout<<"name:"<<t->name<<endl;
		findx(t->left,co);
		findx(t->right,co);
	}
}


Algorithm-greedy2.cpp

// Algorithm-greedy2.cpp : 定义控制台应用程序的入口点。
//
//主要实现赫夫曼编码
#include "stdafx.h"
#include"Huffman.h"
#include"Huffman.cpp"
#include<iostream>
#include<string>
#include<list>
#include<vector>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
	Huffmancode<string> c;
	c.insert("a",10);
	c.insert("e",15);
	c.insert("i",12);;
	c.insert("s",3);
	c.insert("t",4);
	c.insert("p",13);
	c.insert("n",1);
	c.huffcode();
	c.findcode("a");//查找字符为a的赫夫曼码
	c.find("11010");//查找赫夫曼码对应的字符
	return 0;
	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值