计算机算法分析与设计(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.rhkb.cn/news/167069.html

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

相关文章

【Matlab】三维绘图函数汇总

本文用于汇总 Matlab 中的三维绘图函数。plot3() 函数用于绘制用参数方程表示的三维曲线。ezplot3() 函数用于三维曲线的符号绘图&#xff0c;需要用参数方程表示。mesh() 函数用于绘制三维曲面网格。surf() 函数用于绘制三维空间曲面。 目录 1. plot3() 2. ezplot3() 3. me…

R文件详细介绍、瘦身方案和原理

文章目录 1. 背景2. R文件介绍2.1 R文件概念2.1.1 标识符是怎么与资源联系起来的&#xff1f; 2.2 R文件内容2.3 library module和aar的R文件内容生成规则2.4 是谁生成的R文件&#xff1f;2.5 打包之后的R文件2.6 R文件为啥大&#xff1f;这么多&#xff1f; 3. 为什么R文件可以…

【Objective-C】浅析Block及其捕获机制

目录 Block的基本使用Block的声明Block的实现Block的调用 Block作为形参使用Block作为属性使用给Block起别名Block的copy Block的捕获机制auto类型的局部变量__block浅析static类型的局部变量全局变量 其他问题 Block的基本使用 什么是Block&#xff1f; Block &#xff08;块…

2.2.C++项目:网络版五子棋对战之数据管理模块的设计

文章目录 一、数据管理模块实现&#xff08;一&#xff09;功能 二、设计&#xff08;一&#xff09;数据库设计&#xff08;二&#xff09;创建user_table类 一、数据管理模块实现 &#xff08;一&#xff09;功能 数据管理模块主要负责对于数据库中数据进行统一的增删改查管…

【快速解决】在vs2022中配置SFML图形库

目录 SFML 图形库的安装步骤如下&#xff1a; 1.下载 SFML 在 SFML 的官网&#xff08;下载对应操作系统版本的 SFML&#xff09;。​编辑 2.解压文件 将下载的压缩包解压至任意位置&#xff0c;得到类似如下的目录结构&#xff1a; 3.配置 VS 打开 Visual Studio&#xff…

人工智能、机器学习、深度学习的区别

人工智能涵盖范围最广&#xff0c;它包含了机器学习&#xff1b;而机器学习是人工智能的重要研究内容&#xff0c;它又包含了深度学习。 人工智能&#xff08;AI&#xff09; 人工智能是一门以计算机科学为基础&#xff0c;融合了数学、神经学、心理学、控制学等多个科目的交…

深度学习_3_实战_房价预测

梯度 实战 代码&#xff1a; # %matplotlib inline import random import torch import matplotlib.pyplot as plt # from d21 import torch as d21def synthetic_data(w, b, num_examples):"""生成 Y XW b 噪声。"""X torch.normal(0,…

Java EE-servlet API 三种主要的类

上述的代码如下&#xff1a; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.i…

使用CMake构建一个简单的C++项目

文章目录 一. 构建一个简单的项目二. 构建过程1. 创建程序源文件2. 编写CMakeList.txt文件3. 构建项目并编译源代码 附件 一. 构建一个简单的项目 最基本的CMake项目是从单个源代码文件构建的可执行文件。对于像这样的简单项目&#xff0c;只需要一个包含三个命令的CMakeLists…

查看当前cmake版本支持哪些版本的Visual Studio

不同版本的的cmake对Visual Studio的版本支持不同&#xff0c;以下图示展示了如何查看当前安装的cmake支持哪些版本的Visual Studio。 1.打开cmake-gui 2.查看cmake支持哪些版本的Visual Studio

django基于Python的房价预测系统+爬虫+大屏可视化分析

欢迎大家点赞、收藏、关注、评论 文章目录 前言一、项目介绍二、开发环境三、功能需求分析1 数据采集功能设计2数据管理功能设计3爬虫功能需求分析4 数据可视化功能需求分析数据库表的设计 四、核心代码五、效果图六、文章目录 前言 房价是一个国家经济水平的重要体现&#xff…

正点原子嵌入式linux驱动开发——Linux并发与竞争

Linux是一个多任务操作系统&#xff0c;肯定会存在多个任务共同操作同一段内存或者设备的情况&#xff0c;多个任务甚至中断都能访问的资源叫做共享资源。在驱动开发中要注意对共享资源的保护&#xff0c;也就是要处理对共享资源的并发访问。在Linux驱动编写过程中对于并发控制…

2、Kafka 生产者

3.1 生产者消息发送流程 3.1.1 发送原理 在消息发送的过程中&#xff0c;涉及到了两个线程——main 线程和 Sender 线程。在 main 线程 中创建了一个双端队列 RecordAccumulator。main 线程将消息发送给 RecordAccumulator&#xff0c; Sender 线程不断从 RecordAccumulator 中…

为什么短信验证码要设置有效期?

安全性&#xff1a;验证码的主要目的是为了验证用户的身份&#xff0c;防止恶意或未经授权的访问。如果验证码没有有效期&#xff0c;恶意用户或攻击者可以获取验证码后无限期地尝试使用它。通过设置有效期&#xff0c;可以限制验证码的生命周期&#xff0c;提高系统的安全性。…

跳跃游戏Ⅱ-----题解报告

题目&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 与Ⅰ不同的是&#xff0c;这次要求找出最小的跳跃次数。思路也很简单&#xff0c;在每一次跳跃之后都更新最远的跳跃距离。 举个列子&#xff1a; 输入&#xff1a;2,3,1,1,4 第一次…

看我为了水作业速通C++!

和java不太一样的一样的标题打个*&#xff0c;方便对比 基本架构* #include<iostream> using namespace std; int main() { system("pause"); return 0; } 打印* cout << "需要打印的内容" <<endl endl 是一个特殊的输出流控…

【Java基础面试三十八】、请介绍Java的异常接口

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;请介绍Java的异常接口 …

JAVA高级教程-Java Map(6)

目录 6、Map的使用 6、Map的使用 package Map01;import java.util.HashMap; import java.util.Map; import java.util.Set;/*** Map接口的使用*/ public class Demo01_HashMap {public static void main(String[] args) {Map<String,String> mapnew HashMap<>();ma…

Hadoop3教程(三十一):(生产调优篇)异构存储

文章目录 &#xff08;157&#xff09;异构存储概述概述异构存储的shell操作 &#xff08;158&#xff09;异构存储案例实操参考文献 &#xff08;157&#xff09;异构存储概述 概述 异构存储&#xff0c;也叫做冷热数据分离。其中&#xff0c;经常使用的数据被叫做是热数据&…

Android12之DRM架构(一)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…