0023算法笔记——【贪心算法】哈夫曼编码问题

    1、成绩叙述

      哈夫曼编码是到国外地用于标明文献紧缩的特有的无效的编码办法。紧缩率通常在20%到90%当中。。哈夫曼编码算法措词符在文献中涌现的频率表来优美的体型单独用0,1个字母行表现每个字母的最佳效果表现。。单独遏制100个,000个字母文献,每个字母的频率差数。,下表显示。


    文献中有多种表现通讯的办法。,条件0,1码表现字母的一种办法,更确切地说,每个字母应用产物却的0。,1串表现法。条件采取经常地浆糊编码表现,您需求3位来表现单独字母。,总数文献加密需求300,000位;条件采取加长编码表现,一种高频字母的短码;低频字母长编码,取得片面编码的目的,则总数文献编码需求(45×1+13×3+12×3+16×3+9×4+5×4)×1000=224,000位,从其可见,可加浆糊编码优于固经常地浆糊度编码。,加密的总浆糊增加了大概25%。。

     前缀码为每个字母明确提出0。,1个字母行用作它们的加密,而且请求一些字母的加密过失一些及其他字母的前缀。。此加密称为前缀加密。。编码的前缀质量可以使译码办法异常复杂;诸如,001011101可以被产物却分析为0。,0,101,1101,因而它的解码是AABE。

     译码转换需求手边的的取出编码的前缀,像这样,您需求正式的的标明构图来表现前缀加密。。职此之故,两叉树可以用作标明构图的前缀加密。:翻书代表同意的的字母。;从根到叶的某方面用作字母的前缀加密。;加密射中靶子零点或零点充任单独工序卡来指导摇头。。


    从下面的数字可以看出,表现最佳效果前缀加密的二叉树永远单独充分的BI。,更确切地说,树射中靶子一些杂种都有2个家伙。。图A揭晓固经常地浆糊度编码规划过失最优的。,其编码的两叉树过失完整的两叉树。。在一般情况下,条件C是编码字母集,二叉树中有准确的的C叶表现其最优p。。每个叶对应于字母集射中靶子字母。,两叉树具有C—1胸怀难题。。

    同意的的编码字母集C和频率散布f,更确切地说,C射中靶子一些字母C都涌现时频率f(c)的标明文献中。。C的前缀编码规划对应于二叉树T。。树T中字母C的吃水为D。T(c)。dT(c)亦字母C的前缀码浆糊。。则平均分配码长限界为:最少的平均分配码长的前缀编码规划称为C 
   

     2、Haffman码的排列

    哈夫曼排列最优前缀码的饕算法,从其发生的编码规划称为哈夫曼编码。其次的破土使移近如次:

    (1)哈夫曼算法排列了表现最优解的二叉树T。。

    (2)算法从C叶杂种开端。,处死C- 1兼并手柄使产生终极需求的树T。。

    (3)同意编码字母射中靶子每个字母C的频率。以f为键指定的头等队列Q用在饕选择时无效地决定算法目前的要兼并的2棵具有最小频率的树。一旦兼并了最小频率的2棵树,制造一棵新树,频率兼并的2棵树的频率。,并将新树拔出头等级队列Q中。N-1次兼并后,在头等队列中只剩一棵树。,这是贫穷的树T。。

      破土转换如图所示。:


    详细加密取得如次:

     (1),顺序主文献

//4d4 饕算法 哈夫曼算法
#include ""
#include ""
#include ""
#include  
using namespace std; 

const int N = 6;

template class Huffman;

template 
BinaryTree HuffmanTree(Type f[],int n);

template 
class Huffman
{
	friend BinaryTree HuffmanTree(Type[],int)
	public:
		operator Type() const 
		{
			return weight;
		}
	//private:
		BinaryTree tree;
		Type weight;
};

int main()
{
	char c[] = {''0'',A,''b'',''c'',''d'',''e'',''f''};
	int f[] = {0,45,13,12,16,9,5 };//下标从1开端
	BinaryTree t = HuffmanTree(f,N);

	cout<<"各字母涌现的对应频率分别为:"<
BinaryTree HuffmanTree(Type f[],int n)
{
使产生单杂种树
	Huffman *w = new Huffman[n+1];
	BinaryTree z,zero;

为(int) i=1; i<=n; i++)
	{
		(i,zero,zero);
		w[i].weight = f[i];
		w[i].tree = z;
	}

	//建头等队列
	MinHeap> Q(n);
为(int) i=1; i<=n; i++) (w[i]);

	//反复兼并最小频率树
	Huffman x,y;
为(int) i=1; i

     (2) 两叉树取得

#include
using namespace std;

template
struct BTNode
{
	T data;
	BTNode *lChild,*rChild;

	BTNode()
	{
		lChild=rChild=NULL;
	}

	BTNode(const T &val,BTNode *Childl=NULL,BTNode *Childr空)
	{
		data=val;
		lChild=Childl;
		rChild=Childr;
	}

	BTNode* CopyTree()
	{
		BTNode *nl,*nr,*nn;

		if(&data=空)
		return NULL;

		nl=lChild->CopyTree();
		nr=rChild->CopyTree();

		nn=new BTNode(标明),nl,生胶)
		return nn;
	}
};


template
class BinaryTree
{
	public:
		BTNode *root;
		BinaryTree();
		~BinaryTree();

		void Pre_Order();
		void In_Order();
		void Post_Order();

		int TreeHeight()const;
		int TreeNodeCount()const;

		void DestroyTree();
		void MakeTree(T PDATA,BinaryTree leftTree,BinaryTree rightTree);
		void Change(BTNode *r);

	private:
		void Destroy(BTNode *&r);
		void PreOrder(BTNode *r);
		void InOrder(BTNode *r);
		void PostOrder(BTNode *r);

		int 高地(常数) BTNode r)常数
		int NodeCount(const BTNode r)常数
};

template
BinaryTree::BinaryTree()
{
	root=NULL;
}

template
BinaryTree::~BinaryTree()
{
	
}

template
void BinaryTree::Pre_Order()
{
前序(根)
}

template
void BinaryTree::In_Order()
{
按序(根)
}

template
void BinaryTree::Post_Order()
{
PostOrder(根)
}

template
int BinaryTree::TreeHeight()const
{
	return 高地(根)
}

template
int BinaryTree::TreeNodeCount()const
{
	return NodeCount(root);
}

template
void BinaryTree::DestroyTree()
{
缺口(根)
}

template
void BinaryTree::PreOrder(BTNode *r)
{
条件(r)!空)
	{
		cout<data<<'' '';
		PreOrder(r->小孩)
		PreOrder(r->rChild);
	}
}

template
void BinaryTree::InOrder(BTNode *r)
{
条件(r)!空)
	{
		InOrder(r->小孩)
		cout<data<<'' '';
		InOrder(r->rChild);
	}
}

template
void BinaryTree::PostOrder(BTNode *r)
{
条件(r)!空)
	{
		PostOrder(r->小孩)
		PostOrder(r->rChild);
		cout<data<<'' '';
	}
}

template
int BinaryTree::NodeCount(const BTNode r)常数
{
条件(r)=空)
		return 0;
	else
		return 1+NodeCount(r->lChild)+NodeCount(r->rChild);
}

template
int BinaryTree::高地(常数) BTNode r)常数
{
条件(r)=空)
		return 0;
	else
	{
		int lh,rh;
		lh=Height(r->小孩)
		rh=Height(r->rChild);
		return 1+(lh>rh?lh:rh);
	}
}

template
void BinaryTree::Destroy(BTNode *&r)
{
条件(r)!空)
	{
		Destroy(r->小孩)
		Destroy(r->rChild);
		delete r;
		r=NULL;
	}
}

template
void BinaryTree::Change(BTNode R)/ /好转二元系树中占有杂种的摆布子树
{
	BTNode *p;
条件(r)){ 
		p=r->lChild;
		r->lChild=r->rChild;
		r->rChild=p; 摆布小孩交流
		Change(r->小孩)  好转左子树上占有杂种的左、右子树
		Change(r->rChild);  //好转右子树上占有难题的摆布子树
	}
}

template
void BinaryTree::MakeTree(T PDATA,BinaryTree leftTree,BinaryTree rightTree)
{
	root = new BTNode();
	root->data = PDATA;
	root->lChild = leftTree.root;
	root->rChild = rightTree.root;
}

     (3) 最小堆取得

#include 
using namespace std;
template
class MinHeap
{
	private:
		T *heap; //元素街区,臀部0亦单独贮存器单元
		int CurrentSize; 目前的元素数
		int MaxSize; 可控制的最大元素数

		void FilterDown(const int start,const int 完毕) 左右健康状态,使关键词小的杂种
		void FilterUp(int 开端) 从下

	public:
		MinHeap(int n=1000);
		~MinHeap();
		bool 拔出(const) T &x); //拔出元素

		T RemoveMin(); 剔除最小元素
		T GetMin(); 取最小元素

		bool IsEmpty() const;
		bool 大量存在的 const;
		void Clear();
};

template
MinHeap::MinHeap(int n)
{
	MaxSize=n;
	heap=new T [最大按大块排列]
	CurrentSize=0;
}

template
MinHeap::~MinHeap()
{
	delete []heap;
}

template
void MinHeap::FilterUp(int 开端) 从下
{
	int j=start,i=(j-1)/2; 得分父杂种的父杂种
	T temp=heap[j];

(j)>0)
	{
条件(堆)<=temp)
			break;
		else
		{
			heap[j]=heap[i];
			j=i;
			i=(i-1)/2;
		}
	}
	heap[j]=temp;
}

template
void MinHeap::FilterDown(const int start,const int 完毕) 左右健康状态,使关键词小的杂种
{
	int i=start,j=2*i+1;
	T temp=heap[i];
(j)<=完毕)
	{
		if( (j<完毕) && (heap[j]>heap[j+1]) )
			j++;
条件(气温)<=heap[j])
			break;
		else
		{
			heap[i]=heap[j];
			i=j;
			j=2*j+1;
		}
	}
	heap[i]=temp;
}

template
bool MinHeap::拔出(const) T &x)
{
	if(CurrentSize==MaxSize)
		return false;

堆[目前的大块]=x
	FilterUp(CurrentSize);

	CurrentSize++;
	return true;
}

template
T MinHeap::RemoveMin( )
{
	T x=堆〔0〕
堆〔0〕=堆[Currunsisi-1]

	CurrentSize--;
	FilterDown(0,CurrentSize-1); 健康状态新根杂种

	return x;
}

template
T MinHeap::GetMin()
{
	return 堆〔0〕
}

template
bool MinHeap::IsEmpty() const
{
	return CurrentSize==0;
}

template
bool MinHeap::大量存在的 const
{
	return CurrentSize==MaxSize;
}

template
void MinHeap::Clear()
{
	CurrentSize=0;
}

     3、饕选择质量

    两叉树T代表字母集C的最佳效果前缀码,使宣誓了经过修正t相近可以利润单独新的二叉树T。,在T,X和Y是最深的翻书,是情同手足的。,同时,由t表现的前缀码亦最佳效果预FI。。设置B和C是两叉树T的最深叶。,情同手足的们。设f(b)<=f(c),f(x)<=f(y)。由于x和y是C中具有最小频率的两个字母,有f(x)<=f(b),f(y)<=f(c)。首先,在树T中好转翻书b和x的臀部利润T'',之后再树T''中好转翻书c和y的臀部,利润树T''''。如图所示:


    从其可知,TE前缀码的平均分配加密浆糊当射中靶子离题:


     像这样,由t’表现的前缀码亦最佳效果前缀码。,且x,y具有同一的的加密浆糊,同时,只要最佳效果的一位编码是差数的。

     4、最优子构图质量

    两叉树T代表字母集C的最佳效果前缀码,x和y是树T射中靶子两个翻书情同手足的们,Z是他们的生产者。条件Z被处置为具有f(z)=f(x) f(y)的字母,之后树t’=t- {x,y}表现字母集c'= C-{x, y} ∪ { Z}的最佳效果前缀码。像这样,有:


    条件t’过失C’最佳效果前缀码,同意t是C’的最佳效果前缀码,因而有,显然T是单独比T上进的前缀加密。,与必须先具备的的否认!像这样,由t’表现的c'前缀码是最好的。。

    从贪心专一性和最优解衍生哈夫曼算法是本来的的。,HuffmanTree使产生的最优前缀编码树。

    顺序运转产物:

NameE-mailWebsiteComment

发表评论

电子邮件地址不会被公开。 必填项已用*标注