计算机算法分析与设计(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镜像下载到本地,并导入服务器
应用场景 : 本地环境可以连接外网,但服务器连接不了外网,直接用docker pull 命令执行拉起镜像报异常。 1.本地拉取xuxueli/xxl-job-admin:2.2.0及查看所有下载的镜像 docker pull xuxueli/xxl-job-admin:2.2.0 docker images 2.保存镜像到…...

使用VuePress2.X构建个人知识博客,并且用个人域名部署到GitHub Pages中
使用VuePress2.X构建个人知识博客,并且用个人域名部署到GitHub Pages中 什么是VuePress VuePress 是一个以 Markdown 为中心的静态网站生成器。你可以使用 Markdown 来书写内容(如文档、博客等),然后 VuePress 会帮助你生成一个…...

作为过来人,浅谈一下高考、考研、读博
写在前面 由于本人正在读博,标题中的三个阶段都经历过或正在经历,本意是闲聊,也算是给将要经历的读者们做个参考、排雷。本文写于2022年,时效性略有落后,不过逻辑上还是值得大家参考,若所述存在偏颇&#…...

vue3 + vite实现动态路由,并进行vuex持久化设计
在后台管理系统中,如何根据后端返回的接口,来动态的设计路由呢,今天一片文章带你们解 1、在vuex中设置一个方法 拿到完整的路由数据 const state {routerList: []}; const mutations { dynameicMenu(state, payload) {// 第一步 通过glob…...

增量式网络爬虫通用模板
之前做过一个项目,他要求是只爬取新产生的或者已经更新的页面,避免重复爬取未变化的页面,从而节省资源和时间。这里我需要设计一个增量式网络爬虫的通用模板。可以继承该类并重写部分方法以实现特定的解析和数据处理逻辑。这样可以更好的节约…...
【Go语言基础【5】】Go module概述:项目与依赖管理
文章目录 一、Go Module 概述二、Go Module 核心特性1. 项目结构2. 依赖查找机制 三、如何启用 Go Module四、创建 Go Module 项目五、Go Module 关键命令 一、Go Module 概述 Go Module 是 Go 1.11 版本(2018 年 8 月)引入的依赖管理系统,用…...

python打卡day46@浙大疏锦行
知识点回顾: 不同CNN层的特征图:不同通道的特征图什么是注意力:注意力家族,类似于动物园,都是不同的模块,好不好试了才知道。通道注意力:模型的定义和插入的位置通道注意力后的特征图和热力图 内…...
leetcode 2434. 使用机器人打印字典序最小的字符串 中等
给你一个字符串 s 和一个机器人,机器人当前有一个空字符串 t 。执行以下操作之一,直到 s 和 t 都变成空字符串: 删除字符串 s 的 第一个 字符,并将该字符给机器人。机器人把这个字符添加到 t 的尾部。删除字符串 t 的 最后一个 字…...

汽车安全体系:FuSa、SOTIF、Cybersecurity 从理论到实战
汽车安全:功能安全(FuSa)、预期功能安全(SOTIF)与网络安全(Cybersecurity) 从理论到实战的安全体系 引言:自动驾驶浪潮下的安全挑战 随着自动驾驶技术从L2向L4快速演进,汽车安全正从“机械可靠…...
leetcode47.全排列II:HashSet层去重与used数组枝去重的双重保障
一、题目深度解析与重复排列问题 题目描述 给定一个可能包含重复数字的数组nums,返回其所有不重复的全排列。解集不能包含重复的排列,且排列可以按任意顺序返回。例如: 输入:nums [1,1,2]输出:[[1,1,2],[1,2,1],[2…...