计算机算法分析与设计(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(1in) 的重量为 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 串作为其代码,并要求任一字符的代码都不是其它字符代码的前缀,这种编码称为前缀码。

abcdef
编码方式1010110011111011100
编码方式20100011011

 很容易发现,当我们在用编码方式 2 2 2 时,解码会出现问题,例如 00110 00110 00110 既可以解码成 a a b b a aabba aabba,也可以解码成 c f a cfa cfa,解码结果不唯一,编码方式不可行。
 而用前缀码(即编码的任意前缀不是其他编码),则解码结果唯一,编码方式可行。

2.3 问题描述

 1. 如果要求得到最优的编码方式,那不同的前缀码如何比较它们的优劣呢?我们可以通过比较编码后二进制串的总长,总长越短,说明这种编码方式越优。而编码后二进制的总长,依赖于待编码字符的频数。假设我们给出的带编码字符及其频数和两种不同的前缀码,如下表所示。

abcdef
频数(千次)4513121695
前缀码1010110011111011100
前缀码2110011011111001010

 通过计算可知,使用前缀码 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 n1 次合并,运算后产生最终所要求的树 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;	
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/114025.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

昇腾CANN 7.0 黑科技:大模型训练性能优化之道

目前&#xff0c;大模型凭借超强的学习能力&#xff0c;已经在搜索、推荐、智能交互、AIGC、生产流程变革、产业提效等场景表现出巨大的潜力。大模型经过海量数据的预训练&#xff0c;通常具有良好的通用性和泛化性。用户基于“大模型预训练微调”开发范式即可在实际业务场景取…

MySQL——练习

MySQL 一、练习要求二、练习过程 一、练习要求 创建表并插入数据&#xff1a; 字段名数据类型主键外键非空唯一自增idINT是否是是否nameVARCHAR(50)否否是否否glassVARCHAR(50)否否是否否 sch 表内容 id name glass 1 xiaommg glass 1 2 xiaojun glass 21、创建一个可以统计…

PostgreSQL与MySQL数据库对比:适用场景和选择指南

数据库是现代应用程序的基石之一&#xff0c;而在选择合适的数据库管理系统&#xff08;DBMS&#xff09;时&#xff0c;开发者常常会面临着许多选择。在这方面&#xff0c;PostgreSQL和MySQL是两个备受瞩目的选项。本文将深入研究这两者之间的异同&#xff0c;并为您提供适用场…

【使用OpenCV进行目标分割与计数的代码实例详解】

文章目录 概要实例一&#xff1a;硬币分割计数实例二&#xff1a;玉米粒分割计数 概要 在当今数字图像处理领域&#xff0c;图像分割技术是一项至关重要的任务。图像分割旨在将图像中的不同目标或区域准确地分开&#xff0c;为计算机视觉、图像识别和机器学习等领域提供了坚实…

[C语言]排序的大乱炖——喵喵的成长记

宝子&#xff0c;你不点个赞吗&#xff1f;不评个论吗&#xff1f;不收个藏吗&#xff1f; 最后的最后&#xff0c;关注我&#xff0c;关注我&#xff0c;关注我&#xff0c;你会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的很重要…

【微服务 SpringCloud】实用篇 · Ribbon负载均衡

微服务&#xff08;4&#xff09; 文章目录 微服务&#xff08;4&#xff09;1. 负载均衡原理2. 源码跟踪1&#xff09;LoadBalancerIntercepor2&#xff09;LoadBalancerClient3&#xff09;负载均衡策略IRule4&#xff09;总结 3. 负载均衡策略3.1 负载均衡策略3.2 自定义负载…

C++前缀和算法的应用:向下取整数对和 原理源码测试用例

本文涉及的基础知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 题目 向下取整数对和 给你一个整数数组 nums &#xff0c;请你返回所有下标对 0 < i, j < nums.length 的 floor(nums[i] / nums[j]) 结果之和。由于答案可能会…

Kubeadm部署k8s集群 kuboard

目录 主机准备 主机配置 修改主机名&#xff08;三个节点分别执行&#xff09; 配置hosts&#xff08;所有节点&#xff09; 关闭防火墙、selinux、swap、dnsmasq(所有节点) 安装依赖包&#xff08;所有节点&#xff09; 系统参数设置(所有节点) 时间同步(所有节点) 配…

Java面试题-UDP\TCP\HTTP

UDP UDP特性 &#xff08;1&#xff09;UDP是无连接的&#xff1a;发送数据之前不需要像TCP一样建立连接&#xff0c;也不需要释放连接&#xff0c;所以减少了发送和接收数据的开销 &#xff08;2&#xff09;UDP 使用尽最大努力交付&#xff1a;即不保证可靠交付 &#xff0…

Java面向对象(基础)--package和import关键字的使用

文章目录 一、package关键字的使用1. 说明2. 包的作用3. JDK中主要的包 二、import关键字的使用 一、package关键字的使用 1. 说明 package:包package用于指明该文件中定义的类、接口等结构所在的包。语法格式 举例&#xff1a;pack1\pack2\PackageTest.java package pack1.…

Xshell+screen解决ssh连接 服务器掉线的问题

Linux screen命令解决SSH远程服务器训练代码断开连接后运行中断_linux screen ssh-CSDN博客 Linux命令之screen命令_linux screen_恒悦sunsite的博客-CSDN博客 使用教程&#xff1a; 这里粗略介绍一下 &#xff08;1&#xff09;xshell xftp&#xff08;xshell点这个&#…

组合数(递推版)的初始化

初始考虑为将第一列数和斜对角线上的数进行初始化。 橙色方块由两个绿色方块相加而来&#xff0c;一个为1&#xff0c;一个为0&#xff0c;所以斜对角线都为1&#xff0c;可以通过计算得来&#xff0c;不需要初始化&#xff0c;需要与码蹄集盒子与球 第二类Stirling数&#xf…

Go并发编程之一

一、前言 新年学新语言Go系列文章已经完结&#xff0c;用了最简单的例子去了解Go基础语法&#xff0c;但Go最牛B的是它对并发的友好支持&#xff0c;每一门语言都有它自己独特的优势&#xff0c;如Java适合大型工程化项目&#xff0c;Python适合做数据分析及运维脚本&#xff0…

✔ ★【备战实习(面经+项目+算法)】 10.21学习时间表(总计学习时间:5h30min)(算法刷题:7道)

✔ ★【备战实习&#xff08;面经项目算法&#xff09;】 坚持完成每天必做如何找到好工作1. 科学的学习方法&#xff08;专注&#xff01;效率&#xff01;记忆&#xff01;心流&#xff01;&#xff09;2. 每天认真完成必做项&#xff0c;踏实学习技术 认真完成每天必做&…

工具篇之Axure RP 10的使用

引言 最近在学习原型图&#xff0c;针对画原型图的工具&#xff0c;反复对比墨刀、Axure、xiaopiu后&#xff0c;最终选择Axure。 接下来&#xff0c;我便从Axure RP 10的下载、安装、中文字体、授权等几个方面&#xff0c;来介绍Axure。 一、背景 Axure是一款强大的原型设计…

华为OD技术面试-最短距离矩阵(动态规划、广度优先)

背景 记录2023-10-21 晚华为OD三面的手撕代码题&#xff0c;当时没做出来&#xff0c;给面试官说了我的想法&#xff0c;评价&#xff1a;解法复杂了&#xff0c;只是简单的动态规范 或 广度优先算法&#xff0c;事后找资料记录实现方式。 题目 腐烂的橘子 问题描述&#xff…

[SQL | MyBatis] MyBatis 简介

目录 一、MyBatis 简介 1、MyBatis 简介 2、工作流程 二、入门案例 1、准备工作 2、示例 三、Mapper 代理开发 1、问题简介 2、工作流程 3、注意事项 4、测试 四、核心配置文件 mybatis-config.xml 1、environment 2、typeAilases 五、基于 xml 的查询操作 1、…

EtherCAT主站SDO写报文抓包分析

0 工具准备 1.EtherCAT主站 2.EtherCAT从站&#xff08;本文使用步进电机驱动器&#xff09; 3.Wireshark1 抓包分析 1.1 报文总览 本文设置从站1的对象字典&#xff0c;设置对象字典主索引为0x2000&#xff0c;子索引为0x00&#xff0c;设置值为1500。主站通过发送SDO写报文…

STM32-LCD液晶显示

目录 LCD液晶显示 ILI9341液晶控制器简介 液晶屏的信号线和8080时序 使用STM32的FSMC外设模拟8080接口时序 FSMC 功能框图 通讯引脚 存储器控制器 时钟控制逻辑 FSMC的地址映射 FSMC控制异步Nor Flash的时序 FSMC模拟8080时序 FSMC结构体 NOR FLASH时序结构体 F…

由Django-Session配置引发的反序列化安全问题

漏洞成因 漏洞成因位于目标配置文件settings.py下 关于这两个配置项 SESSION_ENGINE&#xff1a; 在Django中&#xff0c;SESSION_ENGINE 是一个设置项&#xff0c;用于指定用于存储和处理会话&#xff08;session&#xff09;数据的引擎。 SESSION_ENGINE 设置项允许您选择不…