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,因而它的解码是阿贝。

     译码议事顺序需求便利的取出编码的前缀,终于,拨的信息构架来表现该请求。因此,这两使杂交树可以用作信息构架的前缀法典。:诸如此类人叶子及梗和枝代表诸如此类人装出的字母。;从树根到叶子及梗和枝的方向作为字母的前缀法典。;法典中每一位的0或1作为诸如此类人指导者来标示到LE的压紧。。


    从上图可以看出。,表现最佳效果前缀法典的两叉树始终诸如此类人使整合的前缀。,就是,树射中靶子诸如此类压紧都有2个小伙子。。图a使知晓固规则浆糊度编码设计变动从而发生断层最优的。,它编码的两叉树变动从而发生断层一棵完整衍生物的树。。在一般情况下,也许C是诸如此类人编码字母集,有在二叉树代表了最好的该不过| C |叶。每小块叶子及梗和枝对应于诸如此类人字母集射中靶子字母。,二叉树的内地压紧| | C 1。

    装出的一组编码字母集c和频率散布f,就是,C C射中靶子诸如此类字母都呈现时频率为f(c)的信息提供免费入场券中。。C的前缀编码设计对应于两叉树t。树射中靶子字母c的吃水是d。T(c)。dT(c)亦字母C的前缀法典浆糊。。则按比例分配码长精确地解释为:前缀法典使按比例分配法典浆糊最小,称为 
   

     2、Havermann编码构架

    坚信礼最优前缀码的哈夫曼渴望的算法,从此发生的编码设计称为哈夫曼编码。以下破土踩如次:

    (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'',' ',''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 *Childrnull)
	{
		data=val;
		lChild=Childl;
		rChild=Childr;
	}

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

		if(&data=null)
		return NULL;

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

		nn=new BTNode(信息,nl,NR)
		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 信息,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 高等(const BTNode R)const
		int NodeCount(const BTNode R)const
};

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!null)
	{
		cout<data<<'' '';
		PreOrder(r->摆布)
		PreOrder(r->rChild);
	}
}

template
void BinaryTree::InOrder(BTNode *r)
{
也许(R!null)
	{
		InOrder(r->摆布)
		cout<data<<'' '';
		InOrder(r->rChild);
	}
}

template
void BinaryTree::PostOrder(BTNode *r)
{
也许(R!null)
	{
		PostOrder(r->摆布)
		PostOrder(r->rChild);
		cout<data<<'' '';
	}
}

template
int BinaryTree::NodeCount(const BTNode R)const
{
也许(R=null)
		return 0;
	else
		return 1+NodeCount(r->lChild)+NodeCount(r->rChild);
}

template
int BinaryTree::高等(const BTNode R)const
{
也许(R=null)
		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!null)
	{
		Destroy(r->摆布)
		Destroy(r->rChild);
		delete r;
		r=NULL;
	}
}

template
void BinaryTree::Change(BTNode r)两个二叉树bt摆布子树替换的自己人压紧
{
	BTNode *p;
也许(R){ 
		p=r->lChild;
		r->lChild=r->rChild;
		r->rChild=p; 摆布孩子们交流
		Change(r->摆布)  替换左、左边的子树的自己人压紧的右子树
		Change(r->rChild);  //替换右子树上自己人难题的摆布子树
	}
}

template
void BinaryTree::MakeTree(T 信息,BinaryTree leftTree,BinaryTree rightTree)
{
	root = new BTNode();
	root->data = 信息;
	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)
	{
也许(堆i)<=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 ] = [ currentsize-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,x和y是最深的叶子及梗和枝,是情同手足的。,同时,用t表现的前缀码亦最佳效果前缀。。B和C是两棵叉树的最深的叶子及梗和枝。,和情同手足的。设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''''。如图所示:


    从此可知,对TRE的前缀编码的按比例分配码长的分别:


     终于,前缀编码T也表现最优前缀码,且x,y具有使相等的法典浆糊,同时,除非最佳效果的一位编码是不同的的。。

     4、最优子构架性格

    两使杂交树T代表字母集C的最佳效果前缀码。,x和y是树T射中靶子两个叶子及梗和枝和情同手足的,Z是他们的老爸。也许z被看待是频率f(z)=f(x) f(y)的诸如此类人字母,与树T = x,表现字母集C =, y} ∪ { z的最佳效果前缀码。终于,有:


    也许t变动从而发生断层C的最佳效果前缀码,准许t是C的最佳效果前缀码,因而有,显然t是比t却更的前缀法典。,必须先具备的没有道理!因而T的c'represented前缀码是最好的。

    引入抢劫的算法的实质,引入哈夫曼算法是特赞的。,最优前缀编码发生的HuffmanTree树。

    顺序运转产物:

发表评论

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