1、贪心算法求解流程:
通常自顶向下设计:做出一个选择(做局部最优选择),然后求解剩下的那个与原问题类似的子问题。
2、贪心算法设计步骤:
3、0-1背包问题与分数背包问题:
0-1背包问题:【动态规划】01背包问题(通俗易懂,超基础讲解)
分数背包问题:贪心算法,见算法导论16.2节
4、赫夫曼编码: 目标:字符出现频率高,使其二进制位数少
对于字符等数据,根据其出现频率,通过赫夫曼贪心算法构造出字符的最优前缀码(二进制表示),从而降低所占空间。
前缀码:没有任何码字是其他码字的前缀。
最优前缀码对应的树有N个叶节点(字符个数),且恰有N-1个内部节点。
4.1、赫夫曼二进制编码构造流程:
a)算法自底向上构造对应最优编码的二叉树T,从N个叶节点开始,执行N-1次合并操作创建最终二叉树。
b)算法使用字符出现频率为关键字的最小优先队列Q,以识别两个最低频率的对象将其合并,
c)合并两对象时得到的新对象频率设置为两原对象频率之和。
流程图如下:
4.2、赫夫曼二进制编码构造C++代码:
假设给定字符及其出现频率组成结构的数组nodeArr
#include <queue>
struct node{
int num; // 字符出现频率
char c; //字符
node* left;
node* right;
node(int x,char y):num(x),c(y),left(null),right(null){}
node():num(0),c('0'),left(null),right(null){}
bool operator< (const node& a){
return num>a.num; //从小到大排列
}
}
node* nodeArr[10]; // 假设已经给定,且存储在动态内存
priority_queue<node*> q; // 按字符出现频率由小到大排列
for(int i = 0;i<10;i++){
q.push(nodeArr[i]);
}
for(int i = 0;i<9;i++){ // 10个节点9条边
node* z = new node;
node* tmp1 = q.front();
q.pop();
node* tmp2 = q.front();
q.pop();
z->left = tmp1;
z->right = tmp2;
z->num = tmp1->num +tmp2->num;
q.push(z);
}
node* root = q.front(); //树的根节点
总结:
1、在构造哈夫曼编码过程中,频率低的放左节点,高的放右节点。
2、哈夫曼编码通过将出现频率高的字符用少数二进制位表示,从而降低使用空间,实现压缩编码。