Huffman算法与解析

版权声明:本文为博主原创文章,转载请附明出处^_^ https://blog.csdn.net/cprimesplus/article/details/89893458

Huffman算法

解决的问题

  ex.在传输电文时,每种字符出现的频率不同,想让电文在能够表达其意思的前提下尽可能短,自然需要让出现频率高的字符占的位数尽可能少。


思想

  Huffman算法的核心是贪心算法。想要达到上面所述的目的,就需要让权重高的字符编码位数尽可能低。
  假设共有五个字符,对应的权重分别是: 12345 12345 ,按照贪心的策略,每次选出频率最小的两个结点构成一棵新的树,再将这棵树的根节点加入到原有序列,这样反复进行直到序列中只有一个根结点,这样得到的目标值就是最小的了(因为频率越低的结点越早执行操作,那么在构建的树中,这个结点所处的层数就越靠下)。

  不难写出其目标函数:
M i n W P L = k = 1 n W k l k Min\quad WPL=\sum_{k=1}^{n}{W_kl_k}
  其中 W P L WPL 为带权路径长度, W k W_k ​代表 k k 叶子结点的权重, l k l_k ​代表从 k k 叶子结点到根的距离。


说明

  既然列表永远保持从小到大顺序,容易想到使用优先队列去保存每棵树的根节点。上面所举的例子共有5个元素,那么优先队列中初始就有5个根节点。而后的操作按照“思想”部分的描述就可以写出。

  由于之前没有自定义过优先队列的优先级,因此使用起来很手生,导致我调了4个小时的错,哭了…
  优先队列的两种表示形式:

  1. priority_queue<ElemType> p;  这是默认格式,默认排序顺序为从大到小
  2. priority_queue<ElemType,存储容器,比较规则> p;

对2的说明:
   从小到大:priority_queue<ElemType,vector<ELemType>,greater<ElemType> > p;
   从大到小:priority_queue<ElemType,vector<ELemType>,less<ElemType> > p;

自定义结构体指针比较规则:

struct st{
	int weight;
};
struct cmp{
	bool operator()(st *&a,  st *&b)
	{
		return a->weight >= b->weight;
	}
};

千万要注意的两点!:

  1. 从小到大写大于号,从大到小写小于号
  2. 哈夫曼算法使用优先队列定义比较级时,要写 &gt; = &gt;= 号!如果只写大于号,加入一个已有的元素到优先队列时,会将这个元素排在优先队列相同元素的后面,这样在Huffman算法中,就可能将子树放在不正当的位置,导致遍历失败,如图。

在这里插入图片描述


代码

#include<iostream>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<stack>
#include<queue>
using namespace std;
const int maxn = 1024;
struct Huffman{
	int weight;
	struct Huffman *left, *right;

	Huffman(int weight){this->weight = weight;}
};
struct cmp{
	bool operator()(Huffman *&a,  Huffman *&b)
	{
		return a->weight >= b->weight;
	}
};
typedef struct Huffman HuffNode;
typedef priority_queue<HuffNode*,vector<HuffNode*>,cmp> Prior;
void Alloc(HuffNode *&p, int weight)
{
	p = (HuffNode *)malloc(sizeof(HuffNode));
	p->weight = weight;
	p->left = NULL;
	p->right = NULL;
}
HuffNode *createHuffNode(Prior a)
{
	HuffNode *res;
	while(!a.empty())
	{
		HuffNode *root;
		Alloc(root, 0);
		HuffNode *t1 = a.top();a.pop();
		if(a.empty())
		{
			res = t1;
			break;
		}
		HuffNode *t2 = a.top();a.pop();	// t1 <= t2
	 	root->left = t1;
		root->right = t2;
		root->weight = t1->weight + t2->weight;
		a.push(root);
	}
	return res;
}
void InOrderWithoutRecursion(HuffNode *root)
{
	HuffNode *p = root;
	stack<HuffNode*> s;
	while(p || !s.empty())
	{
		while(p)
		{
			s.push(p);
			p = p->left;
		}
		if(!s.empty())
		{
			p = s.top();
			cout<<p->weight<<' ';
			s.pop();
			p = p->right;
		}
	}
}
//int index = 0, value[maxn];
void dfs(HuffNode *root, int *mark, int cnt)
{
	if(!root->left && !root->right)
	{
		cout<<root->weight<<" : ";
		for(int i = 0;i < cnt;i++)
			cout<<mark[i]<<' ';
		cout<<endl;
		return;
	}
	mark[cnt] = 0;
	dfs(root->left, mark, cnt+1);
	mark[cnt] = 1;
	dfs(root->right, mark, cnt+1);
} 
int main()
{
	Prior a;	//存放值 
	const int coeff = 10;
	HuffNode *t[coeff];
	int mark[maxn];
	for(int i = 0;i < coeff;i++)
	{
		Alloc(t[i], i+1);
		a.push(t[i]);
	}
	HuffNode *root = createHuffNode(a);
//	InOrderWithoutRecursion(root);
	dfs(root, mark, 0);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/cprimesplus/article/details/89893458