文章目录

  • 1. 贪心算法
  • 2. 应用
    • 2.1 找零钱
    • 2.2 区间覆盖
    • 2.3 霍夫曼编码
      • 霍夫曼编码完整代码

1. 贪心算法

  • 我们希望在一定的限制条件下,获得一个最优解
  • 每次都在当前的标准下做出当下最优决策(整体不一定最优),做出的决策不可以后悔,即不回溯,最终可以得到较为满意的解
  • 贪心算法不追求最优解,节省时间,避免穷尽所有可能

2. 应用

2.1 找零钱

给定金额的找零,用最少张(枚)钱给顾客。(总是优先给大额的)

/*** @description: 贪心应用--找零钱* @author: michael ming* @date: 2019/6/28 22:02* @modified by: */
#include <iostream>
#include <memory.h>
#include <math.h>
#define N 10
using namespace std;
void exchange(float money, float *rmb, int *amount)
{if(money < 0.1)return;int i, k = 0;for(i = 0; i < N; ++i){money = round(money*10)/10.0;//四舍五入掉分k = money/rmb[i];amount[i] = k;money = money-k*rmb[i];}
}
int main()
{float rmb[N] = {100, 50, 20, 10, 5, 2, 1, 0.5, 0.2, 0.1};int amount[N];while(1){memset(amount,0,N*sizeof(int));float money;cout << "请输入要找的钱的金额:";cin >> money;money = round(money*10)/10.0;//四舍五入掉分cout << "找零结果如下(分位四舍五入):" << endl;exchange(money,rmb,amount);int i = 0;while(i < N){if(amount[i] != 0)cout << amount[i] << "个" << rmb[i] << " ";i++;}cout << endl;cout << "----------------------" << endl;}
}

2.2 区间覆盖

运用场景:任务调度,教师排课,学生活动室安排等

在上面图中再加入些区间数据[2,3];[-1,4],[5,12];[4,5],代码实现如下:

/*** @description: 贪心算法--区间覆盖应用* (给定每个人可以在一个房间内活动的时间,要求让最多的人在这个房间活动,打印出这些人)* @author: michael ming* @date: 2019/6/29 23:34* @modified by: */
#include <iostream>
#include <algorithm>
using namespace std;
struct Interval
{int left, right;bool operator<(const Interval &sel_idx) const{if(left == sel_idx.left)return right < sel_idx.right;//左端点相等,取右端小的elsereturn left < sel_idx.left;//左端不等,取左端小的}bool belongto(int l, int r)//区间属于[l,r]的子集{return left >= l && right <= r;}bool absnotbelong(int l, int r)//两个区间完全无重叠{return left >= r || right <= l;}
};
int main()
{const int N = 10;//区间数量int left = 1, right = 10;//大区间左右端点(房间开放时间)int select[N];//存储选出来的区间(人)idint i, j, k, sel_idx = 0;for(i = 0; i < N; ++i){select[i] = -1;}Interval qujian[N] = {{1,5},{2,4},{3,5},{5,9},{6,8},{8,10},{2,3},{-1,4},{5,12},{4,5}};//所有人的占用时间段sort(qujian,qujian+N);//对区间进行排序(先按开始时间早排序,一样早,按占用时间少排前面)for(i = 0; i < N; ++i){if(qujian[i].left >= left && qujian[i].right <= right)//占用时间在开放时间内{while(sel_idx != 0 && !qujian[i].absnotbelong(qujian[select[sel_idx-1]].left,qujian[select[sel_idx-1]].right)){//如果有人占用了房间,一直找到第一个跟他时间不冲突的人++i;}for(k = i, j = k+1; j < N; ++j){//找到时间是不冲突那个人的最小子集的人if(qujian[j].belongto(qujian[k].left,qujian[k].right)){k = j;}}select[sel_idx++] = k;//占用最短的那个人选出来i = k;//从这个人开始再往后找}}cout << "total selected " << sel_idx << " people, their time as following:" << endl;for(i = 0; i < N && select[i] != -1; ++i){//打印被选出来的人的时间信息cout << i << ": [" << qujian[select[i]].left << ","<< qujian[select[i]].right << "]" << endl;}return 0;
}

2.3 霍夫曼编码

  • 假设有一个包含1000个字符的文件,每个字符占1个byte(1byte=8bits),存储这1000个字符一共需要8000bits,有没有更加节省空间的存储方式呢?
  • 假设通过统计发现,这1000个字符中只包含6种不同字符,假设它们分别是a、b、c、d、e、f。而3个二进制位(bit)就可以表示8个不同的字符,a(000)、b(001)、c(010)、d(011)、e(100)、f(101),所以,为了尽量减少存储空间,每个字符我们用3个二进制位来表示。那存储这1000个字符只需要3000bits就可以了,比原来的存储方式节省了很多空间。
  • 还有没有更加节省空间的存储方式呢?
  • 霍夫曼编码,考虑字符的出现频率,频率小的,用长编码,大的,用短编码,使得总体编码长度变短(且由于其编码方式,没有一个字符的编码是另一个的编码的前缀,避免了解码过程中的歧义)


霍夫曼编码完整代码

/*** @description: 贪心应用--霍夫曼编码* @author: michael ming* @date: 2019/6/30 23:53* @modified by: */
#include <string>
#include <vector>
#include <queue>
#include <iostream>
#include <algorithm>
#include <memory.h>#define N 6        //字符集字符种数
using namespace std;
struct htNode//霍夫曼树节点
{char data;//数据类型char code;//数据存放的节点编码unsigned int weight;//数据权值htNode *parent, *lchild, *rchild;//连接节点指针htNode():data('/'),code('\0'),weight(0){parent = lchild = rchild = NULL;}
};
class comp//优先队列比较函数
{public:bool operator()(htNode* &a, htNode* &b)const{if(a->weight == b->weight)return a->data > b->data;return a->weight > b->weight;}
};class HuffmanTree
{public:htNode *root;//根节点指针htNode* node[2*N-1];//N个字符,霍夫曼树节点个数2*N-1priority_queue<htNode*,vector<htNode*>,comp> pri_queue;//优先队列中存放类指针时,第三个参数应该另写一个comp类,类内写operator()void creatTree_outputCode(int *w){char ch = 'a';htNode *left, *right;for(int i = 0; i < N; ++i,++ch){//生成前N个字符节点,输入权重,和字符信息//并放入优先队列(权值小的优先)node[i] = new htNode();node[i]->weight = w[i];node[i]->data = ch;pri_queue.push(node[i]);}for(int i = N; i < 2*N-1; ++i){//后面新生成的N-1个节点node[i] = new htNode();if(pri_queue.top()->data != '/'){//队首的节点不是新生成的,队首放右边right = pri_queue.top();right->code = '1';//右边节点编码1pri_queue.pop();left = pri_queue.top();left->code = '0';//左边节点编码0pri_queue.pop();//左右节点出队}else{//队首是新生成的节点,放左边//(以上if-else保证新生成的节点总在左边)left = pri_queue.top();left->code = '0';pri_queue.pop();right = pri_queue.top();right->code = '1';pri_queue.pop();//左右节点出队}//新节点权值、上下连接指针对接node[i]->weight = left->weight+right->weight;node[i]->lchild = left;node[i]->rchild = right;left->parent = node[i];right->parent = node[i];pri_queue.push(node[i]);//新生成的节点入队}root = pri_queue.top();//最后还剩一个节点,是根节点creatHuffCode();for(int i = 0; i < 2*N-1; ++i)//释放资源{delete node[i];}}void creatHuffCode(){htNode *parent;string huffcode;//霍夫曼编码int codelen = 0;//输入的字符串编码后的总长度bitsfor(int i = 0; i < N; ++i)//遍历前N个字符节点,求其编码{huffcode = "";parent = node[i];//从自己(叶子节点)开始向上找父节点,直到rootcout << i+1 << " " << node[i]->data << " 的霍夫曼编码是: ";while(parent != root)//{huffcode.push_back(parent->code);//将路径中的编码汇成字符串parent = parent->parent;}reverse(huffcode.begin(),huffcode.end());//将最终的编码反转一下cout << huffcode << endl;codelen += huffcode.size()*node[i]->weight;//单字符code长*出现次数}cout << "该字符串的huffman编码长度为: " << codelen << " bits.";}
};int main()
{HuffmanTree huff;cout << "请输入某字符串中" << N << "个字母abc...的权值(频率):" << endl;int w[N];//权重for(int i = 0; i < N; ++i){cout << i+1 << " ";cin >> w[i];//输入权值}huff.creatTree_outputCode(w);//将权值传入并生成Huffman树;生成霍夫曼编码,打印出来return 0;
}

贪心算法(Greedy Algorithm)之霍夫曼编码相关推荐

  1. 贪心算法哈夫曼编码c语言,贪心算法详解:哈夫曼编码

    理解贪心算法 贪心算法是一种算法思想,并不是一个具体的算法,因此我们用两个例子来理解什么样的问题适合用贪心算法解决. 例一 现在有一个能装 100g 物品的背包,和一些可拆分的物品(见表格),怎么装才 ...

  2. 哈夫曼编码压缩率计算_程序员的算法课(8)-贪心算法:理解霍夫曼编码

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/ ...

  3. 贪心算法之最小堆实现霍夫曼编码

    贪心算法之最小堆实现霍夫曼编码 实现之前需要学习的地方: 如果你不了解堆.堆的插入.堆的删除,可以先看下我前面几篇博客 http://blog.csdn.net/u011068702/article/ ...

  4. 程序员的算法课(8)-贪心算法:理解霍夫曼编码

    一.一种很贪婪的算法定义 贪心是人类自带的能力,贪心算法是在贪心决策上进行统筹规划的统称. [百度百科]贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体 ...

  5. 数据结构与算法 / 霍夫曼树、霍夫曼编码和解码

    一. 诞生原因 找出存放一串字符所需的最少的二进制编码. 二. 构造方法 首先统计出每种字符出现的频率,即:概率.权值. 例如:频率表 A:60,    B:45,   C:13   D:69   E ...

  6. Zlib压缩算法:LZ77、LZ78、霍夫曼编码、滑动窗口、Rabin-Karp算法、哈希链、I/O缓冲区

    Table of Contents 1.简介 1.1 什么是zlib 2.压缩算法 2.1 放气 2.2 LZ77 2.2.1 滑动窗口 2.2.2 长距离对 2.3 霍夫曼编码 3. zlib的实现 ...

  7. 霍夫曼算法_霍夫曼编码算法

    霍夫曼算法 In this tutorial, we'll be discussing and implementing the Huffman Coding Algorithm in Java. 在 ...

  8. C语言Huffman Encode霍夫曼编码的算法(附完整源码)

    C语言Huffman Encode霍夫曼编码的算法 C语言Huffman Encode霍夫曼编码的算法完整源码(定义,实现,main函数测试) C语言Huffman Encode霍夫曼编码的算法完整源 ...

  9. 算法科普:有趣的霍夫曼编码

    前言 霍夫曼编码 ( Huffman coding ) 是一种可变长的前缀码.霍夫曼编码使用的算法是 David A. Huffman 还是在MIT 的学生时提出的,并且在 1952 年发表了名为&l ...

最新文章

  1. 【重磅收藏】智源发布《人工智能的认知神经基础白皮书》
  2. mysql的count()函数如何选择索引,千万级表的count()查询优化实例
  3. java按行读取txt文件内容_对txt文件中的内容进行排序
  4. overall error
  5. linux shell 输出到数据库,linux shell 入门
  6. springmvc返回jsp源代码解决办法
  7. 读书笔记_打开量化投资的黑箱06
  8. 【语音识别】基于matlab傅立叶变换0-9数字语音识别【含Matlab源码 384期】
  9. 如何修改CSDN的ID号
  10. mysql是如何设置候选码_求关系模式中的候选键(软考,数据库)
  11. php中关于js保存文件至本地的问题
  12. C程序设计 谭浩强 第十章
  13. 利用python进行数据分析-数据聚合与分组运算2
  14. python实现次梯度(subgradient)和近端梯度下降法 (proximal gradient descent)方法求解L1正则化
  15. php里怎么输入,PHP是怎么进行输入输出的
  16. Vue的滚动条-vue-happy-scroll用法
  17. chinese input
  18. 即兴操作:详解Linux安装GCC方法-------------------------这操作很简单搞一波试试看
  19. 数据分析,如何赋能业务?
  20. ctfshow爆破wp

热门文章

  1. html 替换反斜杠,在URL直接替换反斜杠反斜杠
  2. 群晖docker安装cms_Nas码农篇:群晖Docker安装Gitlab
  3. 编码 括号_Java编码规范整理汇总
  4. mysql设置不区分大小写
  5. innobackupex备份工具
  6. 校内模拟赛 Zbq's Music Challenge
  7. struts2中一些常用的写法 记录
  8. 新浪微博数据网络舆情分析客户端软件
  9. 小白学数据分析-----数据指标 累计用户数的使用
  10. Asp.net 中 Eval 调用后台函数的写法