计算机算法分析与设计(12)---贪心算法(最优装载问题和哈夫曼编码问题)
文章目录
- 一、最优装载问题
- 1.1 问题表述
- 1.2 代码编写
- 二、哈夫曼编码
- 2.1 哈夫曼编码概述
- 2.2 前缀码
- 2.3 问题描述
- 2.4 代码思路
- 2.5 代码编写
一、最优装载问题
1.1 问题表述
1. 有一批集装箱要装上一艘载重量为 c c c 的轮船,已知集装箱 i ( 1 ≤ i ≤ n ) i(1≤i≤n) i(1≤i≤n) 的重量为 w i w_i wi。最优载问题要求在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船。
2. 贪心选择策略:重量最轻者优先装载。
3. 算法思路:将装船过程划分为多步选择,每步装 1 1 1 个货箱,每次从剩下的货箱中选择重量最轻的货箱。如此下去直到所有货箱均装上船或船上不能再容纳其他任何一个货箱。
1.2 代码编写
算法时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
#include<algorithm>
#include<iostream>
using namespace std;int main(){int n; //定义货箱个数int c; //定义船的最大承载量cout<<"输入货箱个数以及船的最大承载量"<<endl;cin>>n>>c;cout<<"输入每件货物的重量"<<endl;int w[n]; //用数组填装货箱的重量for(int i=0;i<n;i++){cin>>w[i];}sort(w,w+n); //快排将货箱的重量由小到大进行排序int temp=0; //中间值int count=0; //计数器for(int i=0;i<n;i++){temp = temp + w[i];if(temp<=c){count++;}else{break;}}cout<<"能装入货箱的最大数量为"<<count<<endl;return 0;
}
二、哈夫曼编码
2.1 哈夫曼编码概述
1. 哈夫曼编码是在电讯通信中的应用之一,广泛地用于数据文件压缩的十分有效的编码方法,其压缩率通常在20%~90%之间。在电讯通信业务中,通常用二进制编码来表示字母或其他字符,并用这样的编码来表示字符序列。
2. 例如:如果需传送的电文为 ‘ A B A C C D A ’ ‘ABACCDA’ ‘ABACCDA’,它只用到四种字符,用两位二进制编码便可分辨。假设 A , B , C , D A, B, C, D A,B,C,D 的编码分别为 00 , 01 , 10 , 11 00, 01,10, 11 00,01,10,11,则上述电文便为 ‘ 00010010101100 ’ ‘00010010101100’ ‘00010010101100’(共 14 位),译码员按两位进行分组译码,便可恢复原来的电文。
2.2 前缀码
1. 前缀码定义:对每一个字符规定一个 0 , 1 0,1 0,1 串作为其代码,并要求任一字符的代码都不是其它字符代码的前缀,这种编码称为前缀码。
| a | b | c | d | e | f | |
|---|---|---|---|---|---|---|
| 编码方式1 | 0 | 101 | 100 | 111 | 1101 | 1100 |
| 编码方式2 | 0 | 1 | 00 | 01 | 10 | 11 |
很容易发现,当我们在用编码方式 2 2 2 时,解码会出现问题,例如 00110 00110 00110 既可以解码成 a a b b a aabba aabba,也可以解码成 c f a cfa cfa,解码结果不唯一,编码方式不可行。
而用前缀码(即编码的任意前缀不是其他编码),则解码结果唯一,编码方式可行。
2.3 问题描述
1. 如果要求得到最优的编码方式,那不同的前缀码如何比较它们的优劣呢?我们可以通过比较编码后二进制串的总长,总长越短,说明这种编码方式越优。而编码后二进制的总长,依赖于待编码字符的频数。假设我们给出的带编码字符及其频数和两种不同的前缀码,如下表所示。
| a | b | c | d | e | f | |
|---|---|---|---|---|---|---|
| 频数(千次) | 45 | 13 | 12 | 16 | 9 | 5 |
| 前缀码1 | 0 | 101 | 100 | 111 | 1101 | 1100 |
| 前缀码2 | 1100 | 1101 | 111 | 100 | 101 | 0 |
通过计算可知,使用前缀码 1 1 1编码后二进制串的总长是 224000 224000 224000,使用前缀码 2 2 2编码后二进制串的总长是 348000 348000 348000,显然,前缀码 1 1 1要优于前缀码 2 2 2。
2. 贪心策略:出现频率较高的字符的编码较短,出现频率较低的字符的编码较长。使用二叉树对其进行编码和解码。

2.4 代码思路
1. 给定编码字符集 C C C 及 C C C 中的任一字符 c c c 的出现频率 f ( c ) f(c) f(c)。 C C C 的一个前缀码编码方案对应一棵二叉树 T T T。字符 c c c 在树 T T T 中的深度记为 d T ( c ) d_T(c) dT(c)。定义该编码方式的平均码长为:


2. 哈夫曼算法以自底向上的方式构造表示最优前缀码的二叉树 T T T。算法以 n n n 个叶结点开始,执行 n − 1 n-1 n−1 次合并,运算后产生最终所要求的树 T T T。在哈夫曼树中,编码字符集中每个字符 c c c的频率是 f ( c ) f(c) f(c)。以 f f f 为键值的优先队列 Q Q Q 在用做贪心选择时有效地确定当前要合并的两棵具有最小频率的树。一旦两棵具有最小频率的树合并后,产生一棵新的树,其频率和为合并的两棵树的频率之和,并将新树加入 Q Q Q。
2.5 代码编写
算法时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
#include<iostream>
using namespace std;#define MaxNode 200
#define MaxBit 100//节点,一般遵循左0右1
typedef struct
{double weight; //权重int parent; //父节点int lchild; //左孩子节点int rchild; //右孩子节点char value; //节点代表的字符
}hufnode;typedef struct
{int start; //开始指针,记录每个字母编码在数组里开始的位置int bit[10]; //存放赫夫曼编码
}hufbit;hufnode hujd[MaxNode];
hufbit hb[MaxBit];//初始化节点,parent,lchild,rchild=-1,weight=0
void initNode()
{for (int i = 0; i < MaxNode; i++){hujd[i].lchild = -1;hujd[i].parent = -1;hujd[i].rchild = -1;hujd[i].weight = 0;}
}//建立哈弗曼树
void creathuf(int n)
{int i;cout << "请输入每个节点的字符和权值" << endl;for (i = 0; i < n; i++){cin >> hujd[i].value >> hujd[i].weight;}//定义两个变量m1和m2用来存储最小的两个未处理的权值,以及两个变量x1和x2用来存储对应的最小权值的节点索引。double m1, m2;int x1, x2;for (int i = 0; i < n - 1; i++){m1 = m2 = 1000;x1 = x2 = 0;for (int j = 0; j < n + i; j++){//找最小权值结点 if (hujd[j].weight < m1 && hujd[j].parent == -1){m2 = m1;x2 = x1;m1 = hujd[j].weight;x1 = j;}//找第二最小权值结点 else if (hujd[j].weight < m2 && hujd[j].parent == -1){m2 = hujd[j].weight;x2 = j;}}//创建一个新的父节点,其左孩子为x1,右孩子为x2 hujd[n + i].weight = m1 + m2;hujd[n + i].lchild = x1;hujd[n + i].rchild = x2;hujd[x1].parent = n + i;hujd[x2].parent = n + i;}
}//编码
void tshuff(int n)
{//p用于保存当前节点的父节点的索引,c用于保存当前节点的索引。int p, c;for (int i = 0; i < n; i++){p = hujd[i].parent; //获取当前节点的父节点索引并赋值给pc = i; //获取当前节点的索引并赋值给chb[i].start = n - 1; //将当前节点的起始位设置为n-1,这可能意味着我们是从最右边开始编码的while (p != -1) //当前节点不是根节点时进行循环{//如果当前节点是父节点的左孩子,我们将起始位处的二进制位设为0,并将起始位右移一位(向树的左边移动)if (hujd[p].lchild == c){hb[i].bit[hb[i].start] = 0;hb[i].start--;}//如果当前节点是父节点的右孩子,我们将起始位处的二进制位设为1,并将起始位右移一位(向树的左边移动if (hujd[p].rchild == c){hb[i].bit[hb[i].start] = 1;hb[i].start--;}//将当前节点的索引赋值给p,将父节点的索引赋值给c,然后开始下一轮循环。//这个过程一直持续到p等于-1为止,也就是说,当我们到达树的根节点时,循环就会结束。c = p;p = hujd[p].parent;}}
}void output(int n)
{for (int i = 0; i < n; i++){cout << hujd[i].value << ":";for (int j = hb[i].start+1; j < n; j++){cout << hb[i].bit[j];}cout << endl;}
}
int main()
{int n;cout << "请输入有几个字符:" << endl;cin >> n;initNode();creathuf(n);tshuff(n);cout << "编码方式为:" << endl; output(n);return 0;
}
相关文章:
计算机算法分析与设计(12)---贪心算法(最优装载问题和哈夫曼编码问题)
文章目录 一、最优装载问题1.1 问题表述1.2 代码编写 二、哈夫曼编码2.1 哈夫曼编码概述2.2 前缀码2.3 问题描述2.4 代码思路2.5 代码编写 一、最优装载问题 1.1 问题表述 1. 有一批集装箱要装上一艘载重量为 c c c 的轮船,已知集装箱 i ( 1 ≤ i ≤ n ) i(1≤i≤…...
打造属于自己的vue图标库
hfex-icon图标库 Install npm i -D hfex-icon主要提供2种使用方式 方式一 通过svg图标资源,借助unplugin-icons库将svg图标文件生成vue组件,然后通过vue组件的引入方式在vue中使用 unplugin-icons 兼容vue2和vue3 在vue.config.js的plugins中配置…...
C++11线程池
使用 condition_variable::wait(unique_lock<mutex>&lck, Predicate pred) 时,必须保证条件变量通过notify唤醒的同时,wait 的第二个参数 Predicate 返回 true 了才可以往下走。必须两个条件同时满足,如果notify的时候Predicate返回…...
企业打造VR虚拟展厅,开启商务洽谈新时代!
现代化数字营销中,企业做了虚拟线上展厅和不做虚拟展厅的对比是很明显的,VR虚拟展厅让企业产品、企业环境、企业实力的展示更加真实、直观。虚拟展厅是一种在线展示企业形象和品牌的新型方式,随着VR技术的发展,虚拟展厅正在逐步取…...
linux部署gitlab
1. 配置yum源: vim /etc/yum.repos.d/gitlab-ce.repo [gitlab-ce] nameGitlab CE Repository baseurlhttps://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el$releasever/ gpgcheck0 enabled1 2. 更新本地缓存 sudo yum install -y gitlab-ce 3. 安装相关依赖 yum …...
c++_learning-基础部分
文章目录 基础认识:语言特性(面向对象编程):c的类(相当于c中的结构体):三大特性:c包含四种编程范式:优缺点: c程序编译的过程:预处理->编译&am…...
支持PC端、手机端、数据大屏端的Spring Cloud智慧工地云平台源码
技术架构:微服务JavaSpring Cloud VueUniApp MySql 智慧建筑工地云平台主要利用大数据、物联网等技术,整合工地信息、材料信息、工程进度等,实现对建筑项目的全程管理。它可以实现实时监测和控制,有效解决施工中的问题,…...
给cmd控制台程序 套壳 美化
给cmd控制台程序套壳美化,可以获取程序的标准输出和报错信息。 # _*_ coding: utf-8 _*_ """ 控制台程序启动器,杜绝黑窗口。 Time: 2023/10/18 15:28 Author: Jyun Version: V 0.1 File: main.py Blog: https://ctrlcv.…...
【系统架构设计】架构核心知识: 1 构件和中间件
目录 一 构件 1 构件的特性 2 构件、对象和模块的对比 3 构件的复用...
通过开发者工具-网络排查响应时间过长的问题
关键词:network 网络 pending 开发者工具 有时候我们会发现某次http请求花费了很长时间,比如会花费十几秒,那么我们可以通过开发者工具的网络和其他一些工具来分析请求时间过长的原因 Dev Tool 中时间线各阶段代表的意义 分别用edge、chorm…...
【Python】Python 实现 Excel 到 CSV 的转换程序
Python 实现 Excel 到 CSV 的转换程序 Excel 可以将电子表格保存为 CSV 文件,只要点几下 鼠标,但如果有几百个 Excel文件要转换为 CSV , 就需要点击几小时。利用 openpyxl 模块, 编程读取当前工作目录中的所有 Excel 文件&#x…...
BUUCTF题解之[极客大挑战 2019]Havefun 1
1.题目分析 使用浏览器开发者工具查看网页源码,查看疑似flag的代码。 (特别是注释了的源码,一般是HTML,JS,PHP的源码) 修改统一资源定位符URL访问服务器后端接口,拿到flag。 1.URL URL是统一资源定位符(…...
DIV+CSS网页布局
本文参考 https://blog.csdn.net/ZhangJiWei_2019/article/details/114669722 二、浮动 浮动的元素会向左或向右浮动,直到碰到前面已经有浮动的元素或者是其父元素的边框为止。浮动的元素会脱离文档流(不再占有原来的位置)。 (…...
python二次开发CATIA:CATIA Automation
CATIA 软件中有一套逻辑与关系都十分严谨的自动化对象,它们从CATIA(Application)向下分支。每个自动化对象(Automation Object,以下简称Object)都有各自的属性与方法。我们通过程序语言调用这些 Object 的属性与方法,便…...
2023年中国云计算软件市场规模、市场结构及市场份额情况分析[图]
云计算是分布式计算的一种,指的是通过网络“云”将巨大的数据计算处理程序分解成无数个小程序,然后,通过多部服务器组成的系统进行处理和分析这些小程序得到结果并返回给用户。云计算软件类型分为三类,即基础设施即服务、平台即服…...
docker入门加实战—部署Java和前端项目
docker入门加实战—部署Java和前端项目 部署之前,先删除nginx,和自己创建的dd两个容器: docker rm -f nginx dd部署Java项目 作为演示,我们的Java项目比较简单,提供了一个接口: 配置文件连接docker里的m…...
机器人制作开源方案 | 行星探测车概述
1. 功能描述 行星探测车(Planetary Rover)是一种用于进行科学探索和勘测任务的无人车辆,它们被设计成能够适应各种复杂的地形条件和极端环境,以便收集数据、拍摄照片、采集样本等。行星探测车通常包含以下主要组件和功能ÿ…...
Git基础命令
一、Git 码云创建空白仓库 什么都不选,使用代码初始化 初始化仓库:git init 配置信息:git config user.name"mashuchao" 配置信息:git config user.email"mashuchao.com" 查看配置信息:git c…...
C#中Semaphore 和 CountdownEvent 的使用总结
信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量。一旦该关键代码段完成了,那么该线程必须释…...
THE PLANETS:EARTH vulnhub
信息收集 netdiscover -i eth0 -r 192.168.239.0,扫描存活主机,发现目标主机 对目标主机进行端口扫描:nmap -p- -sV -O -Pn -A 192.168.239.186,发现443端口存在DNS,域名 在本地得/etc/hosts中添加域名信息 浏览…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
