数据结构与算法设计分析——贪心算法的应用

news2024/11/19 5:57:57

目录

  • 一、贪心算法的定义
  • 二、贪心算法的基本步骤
  • 三、贪心算法的性质
    • (一)最优子结构性质
    • (二)贪心选择性质
  • 四、贪心算法的应用
    • (一)哈夫曼树——哈夫曼编码
    • (二)图的应用——求最小生成树
      • 1、普里姆算法(Prim)
      • 2、克鲁斯卡尔算法(Kruskal)
      • 3、两种算法的比较
    • (三)图的应用——求单源最短路径
      • 迪杰斯特拉算法(Dijkstra)

一、贪心算法的定义

贪心算法是指不考虑整体上的综合最优决策,而在局部上以最优决策来解决问题,即每次选择的都是最优的解决方案,不考虑该决策对整体的影响。这种方法在处理一些情况下,可以得到最优解的很好近似方案,例如,哈夫曼编码、求最小生成树中的普里姆算法(Prim)克鲁斯卡尔算法(Kruskal)、求单源最短路径中的迪杰斯特拉算法(Dijkstra)等算法。

二、贪心算法的基本步骤

  • 首先,对整体最优解采用贪心算法进行分解,将其化为若干个小规模的子问题,这些子问题是相互独立的,然后通过数学归纳法证明,在每一步的选择中,可以依据贪心策略在当前子问题中选择出最优解(局部解决,不考虑整体情况,只考虑当前),最后,将所有子问题的最优解进行整体合并,得到整体的最优解,从而解决问题,简单可归纳为三个步骤。

三、贪心算法的性质

贪心算法具有以下两大性质,若针对某一问题,若具有以下重要性质,则可以通过使用贪心算法可以得到最优解。

(一)最优子结构性质

针对一个问题,将问题分为若干个子问题,从而该问题的最优解分割成若干个子问题的最优解来解决,然后通过递推从而得到该问题的最优解,即最优子结构性质。所以,具有这种性质的问题,才能保证通过贪心算法得到的解是最优解。【可分割,局部】

(二)贪心选择性质

在求解问题时,每一步都采取在当前情况下最优的选择,即每次选择都是在局部中选择最优解,从而最终得到的解是整体最优解(最近似),即贪心选择性质。【局部最优】

四、贪心算法的应用

在《数据结构》中贪心算法的常见应用场景有以下,例如,哈夫曼树中的哈夫曼编码,图的应用中求最小生成树以及求单源最短路径的相关算法。

贪心算法的应用
哈夫曼编码
求最小生成树
普里姆算法
克鲁斯卡尔算法
求单源最短路径
迪杰斯特拉算法

(一)哈夫曼树——哈夫曼编码

注:求哈夫曼编码时,最小频率和最小权值等同,这里以最小权值为例介绍。
简单的来说,哈夫曼编码是可变字长编码(VLC)的一种,常用于数据的压缩,压缩率在20%~90%。哈夫曼树以及哈夫曼编码的基本概念,可以回顾一下之前的文章:数据结构学习笔记——哈夫曼树

例如,画出以3,4,6,8,12,13,15,18,25,40为结点权值所构造的哈夫曼树,并对各结点编码。

解:选取权值最小的两个结点:3和4,相加3+4=7,新的根结点为7,将其插入到树的集合中:
在这里插入图片描述
此时集合中为[6,7,8,12,13,15,18,25,40],继续选取最小的两个结点权值:
在这里插入图片描述
此时集合中为[8,12,13,13,15,18,25,40],继续选取最小的两个结点权值:
在这里插入图片描述
此时集合中为[13,13,15,18,20,25,40],继续选取最小的两个结点权值:
在这里插入图片描述
此时集合中为[15,18,20,25,26,40],继续选取最小的两个结点权值:
在这里插入图片描述
此时集合中为[20,25,26,33,40],继续选取最小的两个结点权值:
在这里插入图片描述
此时集合中为[26,33,40,45],继续选取最小的两个结点权值:
在这里插入图片描述
此时集合中为[40,45,59],继续选取最小的两个结点权值:
在这里插入图片描述
此时集合中为[59,85],继续选取最小的两个结点权值:
在这里插入图片描述
即为最终的哈夫曼树,设左分支为0,右分支为1,如下:
在这里插入图片描述
则各叶子结点的哈夫曼编码如下:
3:00010
4:00011
6:0000
8:1100
12:1101
13:001
15:010
18:011
25:111
40:10

从以上过程中,不难看出,每次的选择都是选取两棵根结点权值最小的树作为左、右子树,新的二叉树的根结点权值为其权值之和,然后将原先两个结点从森林中删除,新的结点添加进去……,按照由下至上依次构造哈夫曼树,最上层的权值最大。
1、哈夫曼编码的最优子结构性质

  • 针对哈夫曼树,对字符进行编码,将要编码的字符作为叶子节点,两两组合,从下往上,通过执行n-1次的合并产生新的根结点,依次进行下去,得到最终的哈夫曼编码。由于每次选择的都是两个最小权值结点,从而构成了一个局部最优解。【局部最优】

n个结点的哈夫曼树可形成共2n-1个结点,且叶子结点的个数也为n,分支结点的个数=总结点数-叶子结点数=2n-1-n=n-1,即有n-1次合并。

2、哈夫曼编码的贪心选择性质

  • 每次选择当前两个或权值最小的结点构造一颗子树的根结点,其权值为权值之和,并把产生的子树的根结点再插入到队列中,最后,按结点的权值大小为最小优先队列。由于每次选择的情况都是最小权值结点,所以这两个结点之和一定是最优解。【选择最优】

(二)图的应用——求最小生成树

简单的来说,含有n个顶点的最小生成树有以下特点:
①最小生成树不唯一;
②最小生成树是一个无环图(不形成回路);
③最小生成树中包含图的所有顶点;
④最小生成树在所有生成树中该树的各边权值之和最小;
⑤最小生成树生成树的边的个数为n-1;

在生成最小生成树时可以选择不同的边,所以最小生成树不唯一(存在权值相同的边),但若当图G的各边权值不同,则此时最小生成树是唯一的,所以最小生成树的边的权值之和总是唯一的。

最小生成树的概念,可以回顾一下之前的文章:数据结构学习笔记——图的应用1(最小生成树、最短路径)

1、普里姆算法(Prim)

普里姆算法的步骤如下:
①从顶点集V中任意选取一个顶点,然后将与该顶点邻接的边中选取一条权值最小的边,将其并入,从而得到一棵树;
②继续选取邻接的边中最短的边(权值最小),连接边,并入树中(若有相同权值,则任选一条即可);
③直到图中的所有顶点都被并入,得到最小生成树。

  • 普里姆算法适用于求边稠密的网的最小生成树,由于每次都是选择一个点与其他剩下点的之间的最短边(最小权值),所以其时间复杂度与图的边数无关,核心语句是在集顶点集V中寻找最近的顶点,所以n个顶点、e条边的无向连通带权图,其时间复杂度为O(n2)。

例如,下面是一个无向带权连通图,采用普里姆算法生成最小生成树:

任意选取一个顶点为起点开始,这里选取V1为例。
在这里插入图片描述
此时邻接的边的权值分别为[2、3、6],取最小权值2,所以V1与邻接的顶点V4相连:
在这里插入图片描述
此时邻接的边的权值分别为1、4、5、5,以及加上前面的3、6,即[1、3、4、5、5、6],取最小权值1,所以V4与邻接的顶点V6相连:
在这里插入图片描述
此时邻接的边的权值分别为3、4,以及加上前面的3、6、4、5、5,即[3、4、4、5、5、6],取最小权值3,V6与邻接的顶点V5相连:
在这里插入图片描述
取此时最小权值,取的是当前图中剩余各边对应权值中最小的权值,即3,V1与V3相连:
在这里插入图片描述
取此时最小权值,即4,V4与V2相连,至此所有顶点都被访问到,得到最小生成树(该最小生成树的代价为3+1+4+2+3=13):
在这里插入图片描述
(1)普里姆算法的最优子结构性质

  • 从上可看出,普里姆算法的核心是每次选择当前顶点(连通)与剩下顶点(未连通)之间的最小权值的边,依次进行,每次选最小,最后得到一棵最小生成树。由于每次选择两个最小权值边,从而构成了一个局部最优解。【局部最优】

(2)普里姆算法的贪心选择性质

  • 由于在每次选择中,都是选择的权值最小的边,所以保证了每一步的选择情况都是当前最优的,从而最终得到的是一棵最小生成树。【选择最优】

2、克鲁斯卡尔算法(Kruskal)

克鲁斯卡尔算法的步骤如下:
①先将图的所有边对应的权值按照从小到大的顺序排序;
②选择其中权值最小的边加入并连接,并入树中,若选取的某边与先前的树构成回路(环),则舍去;
③一直进行下去,权值以小到大,直到所有顶点被访问到,得到最小生成树。

  • 克鲁斯卡尔算法适用于求边稀疏的网的最小生成树,核心语句是将e条边从小到大依次排序,所以n个顶点、e条边的无向连通带权图,其时间复杂度为O(eloge)。

例如,下面是一个无向带权连通图,采用克鲁斯卡尔算法生成最小生成树:

在这里插入图片描述
将图中所有边对应的权值,按从小到大排序如下:1,2,3,4,5,6,8。
可知权值1最小,首先连接V4和V6:
在这里插入图片描述
3、选择权值2,连接V6与V5:
在这里插入图片描述
3、选择权值3,选取V4与V1连接:
在这里插入图片描述
4、选择权值4,连接V1与V3:
在这里插入图片描述
5、选取权值5,连接V4与V2,最终得到最小生成树如下(该最小生成树的代价为4+3+1+5+2=15):
在这里插入图片描述
(1)克鲁斯卡尔算法的最优子结构性质

  • 克鲁斯卡尔算法中由于权值已经顺序排列,所以依次进行,每次加入的都是当前最小的边,构成的都是当前的一个连通分量的最小生成树(该顶点到其他顶点的最小生成树),最后得到整个图的最小生成树。由于事先已排序好,每次选择的是当前最小权值边,从而构成了一个局部最优解。【局部最优】

(2)克鲁斯卡尔算法的贪心选择性质

  • 由于在每次选择中,都是选择的权值最小的边且保证不会成回路(环),若不满足该条件,则说明当前情况不是最优,所以保证了在每一步的选择情况都是当前最优的,从而最终得到的是一棵最小生成树。【选择最优】

3、两种算法的比较

名称比较
普里姆算法一次次
克鲁斯卡尔算法整体

普里姆算法是每次选取一个最短边,即针对顶点,只能得到该顶点到其他顶点的最小生成树,当需要求图的最小生成树时,需要一次次的普里姆算法才能得到最小生成树,而克鲁斯卡尔算法由于一开始就将边的权值按从小到大依次排序,是从整体上出发,所以可以直接得到最小生成树,另外,由于需要对所有的边进行排序,其占用的空间也比普里姆算法多,空间复杂度为O(n)。

(三)图的应用——求单源最短路径

迪杰斯特拉算法(Dijkstra)

迪杰斯特拉算法计算的是在一个有向带权图中,指定一个源点到其他所有顶点的最短路径长度,即最短路径,而单源最短路径一般通过迪杰斯特拉算法解决。

在带权图中,一个顶点到另一个顶点所经过边的权值之和称为该路径的带权路径长度,由于可能路径不止一条,所以将带权路径长度最短的那条路径称为最短路径。

迪杰斯特拉算法的步骤如下:
①通过一个数组存储源点到每个顶点的距离;
②依次选取源点当前未访问到的所有顶点中距离最短的顶点,然后更新该顶点相邻的顶点与源点的距离;
③重复过程,直到所有顶点都被访问到。

  • 克鲁斯卡尔算法中的核心语句是寻找距离源点最近的顶点,所以n个顶点的有向带权图,其时间复杂度为O(n2),另外由于需要数组存放带权邻接矩阵,所以空间复杂度为O(n)。

(1)迪杰斯特拉算法的最优子结构性质

  • 在每次更新该顶点相邻的顶点与源点的距离时,当前所有的顶点与源点的最短路径是最优的,从而构成了一个局部最优解。【局部最优】

(2)迪杰斯特拉算法的贪心选择性质

  • 由于每次选择的都是源点当前未访问到的所有顶点中距离最短的顶点,保证选择的都是当前距离最短,从而得到的是最短路径。【选择最优】

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

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

相关文章

《Linux 内核设计与实现》13. 虚拟文件系统

通用文件接口 VFS 使得可以直接使用 open()、read()、write() 这样的系统调用而无需考虑具体文件系统和实际物理介质。 好处:新的文件系统和新类型的存储介质需要挂载时,程序无需重写,甚至无需重新编译。 VFS 将各种不同的文件系统抽象后采…

[强网杯 2022]factor有感

可直接私信+Q 3431550587 此题记录主要是他运用了几个新看见的攻击思路和拜读了一篇论文,所以写写。题目源码: #encoding:utf-8 from Crypto.Util.number import * from gmpy2 import * from random import randint from flag import flagd…

云服务仿真:完全模拟 AWS 服务的本地体验 | 开源日报 No.45

localstack/localstack Stars: 48.7k License: NOASSERTION LocalStack 是一个云服务仿真器,可以在您的笔记本电脑或 CI 环境中以单个容器运行。它提供了一个易于使用的测试/模拟框架,用于开发云应用程序。主要功能包括: 在本地机器上完全…

CTF之CTF(夺旗赛)介绍

什么是CTF? CTF(Capture The Flag,中文一般译作“夺旗赛”)在网络安全领域中指的是网络安全技术人员之间进行技术竞技的一种比赛形式。CTF起源于1996年DEFCON全球黑客大会,用以代替之前黑客们通过互相发起真实攻击进行…

最新AI智能创作系统源码SparkAi系统V2.6.3/AI绘画系统/支持GPT联网提问/支持Prompt应用/支持国内AI模型

一、智能AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统,已支持OpenAIGPT全模型国内AI全模型,已支持国内AI模型 百度文心一言、微软Azure、阿里云通义千问模型、清华智谱AIChatGLM、科大讯飞星火大模型等。本期针对源码…

Javascript - 轮播图

轮播图也称banner图、广告图、焦点图、滑片。是指在一个模块或者窗口,通过鼠标点击或手指滑动后,可以看到多张图片。这些图片统称为轮播图,这个模块叫做轮播模块。可以通过运用 javascript去实现定时自动转换图片。以下通过一个小Demo演示如何运用Javascript实现。 <!DOCTYP…

d3dcompiler_47.dll是什么文件?游戏确实d3dcompiler_47.dll的常用解决方法

d3dcompiler_47.dll 是一个动态链接库&#xff08;DLL&#xff09;文件&#xff0c;属于 Microsoft DirectX 软件组件的一部分。它主要负责处理 DirectX 中的图形和多媒体内容&#xff0c;以确保游戏和应用程序能够正常运行。d3dcompiler_47.dll 的主要功能是将 DirectX API 转…

基于SpringBoot的在线宠物用品交易网站

目录 前言 一、技术栈 二、系统功能介绍 用户信息管理 商品分类管理 品牌信息管理 商品信息管理 商品信息 我的收藏 我的订单 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实…

C++设计模式-组合(Composite)

目录 C设计模式-组合&#xff08;Composite&#xff09; 一、意图 二、适用性 三、结构 四、参与者 五、代码 C设计模式-组合&#xff08;Composite&#xff09; 一、意图 将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的…

stm32之手动创建keil工程--HAL库

用CubeMx创建了好多stm32的工程&#xff0c;这里记录下手动创建keil工程的过程。 一、准备工作 1.1、下载对应的HAL库&#xff0c; 这里使用的是stm32f103c8t6, 下载地址stm32HAL库 在页面中输入对应型号点击进行二级页面进行下载 1.2、准备工程 各文件夹下具体操作如下&am…

Qt之QDial(表盘)

简介 QDial类提供了一个四舍五入的范围控制&#xff08;如速度计或电位计&#xff09;&#xff0c;非常适合需要循环计数的情况&#xff0c;例如角度等。 头文件&#xff1a;#include <QDial> qmake&#xff1a;QT widgets 继承&#xff1a;QAbstractSlider …

在WIN10平台上体验Microsoft古老的Quick C 1.0编程

前言&#xff1a; 90年代初&#xff0c;微软出了Quick系统对抗Borland Turbo系列&#xff0c;其中包括 QuickBasic, QuickPascal和Quick C。1991年&#xff0c;Quick C for Windows 1.0发布&#xff0c;后来它被Visual C取代。我自己觉得微软成就在那个winstub.exe桩上&#xf…

连接虚拟机工具推荐

连接虚拟机工具推荐 连接虚拟机的工具有很多种&#xff0c;以下是一些常用的推荐&#xff1a; PuTTY&#xff1a;这是一个非常常用的SSH和telnet客户端&#xff0c;适用于Windows系统。它允许你在本地机器上通过命令行接口远程登录到虚拟机。 SecureCRT&#xff1a;这是一个支…

vscode 配置自定义code snippets 来快速生成你的常用代码

一、功能介绍 什么是 snippets 功能&#xff1f; 其实大家可能体验过vscode 预先内置的许多 snippets, 比如 for 循环。 在输入 for Tab 的时候&#xff0c;就可以自动生成代码模版&#xff0c; 展开就是这样的代码 有一个小窍门是通过 tab 键可以在参数之间进行跳转&#xf…

力扣 -- 1745. 分割回文串 IV

解题步骤&#xff1a; 参考代码&#xff1a; class Solution { public:bool checkPartitioning(string s) {int ns.size();vector<vector<bool>> dp(n,vector<bool>(n));for(int in-1;i>0;i--){for(int ji;j<n;j){if(s[i]s[j]){dp[i][j]i1<j?dp[i…

【C++设计模式之观察者模式:行为型】分析及示例

简介 观察者模式&#xff08;Observer Pattern&#xff09;是一种行为型设计模式&#xff0c;它定义了一种一对多的依赖关系&#xff0c;使得当一个对象的状态发生变化时&#xff0c;所有依赖它的对象都能够自动收到通知并更新。 描述 观察者模式由两个核心件组成&#xff1…

抄写Linux源码(Day18:读取硬盘前的准备工作有哪些?)

回忆我们需要做的事情&#xff1a; 为了支持 shell 程序的执行&#xff0c;我们需要提供&#xff1a; 1.缺页中断(不理解为什么要这个东西&#xff0c;只是闪客说需要&#xff0c;后边再说) 2.硬盘驱动、文件系统 (shell程序一开始是存放在磁盘里的&#xff0c;所以需要这两个东…

[论文精读]U-Net: Convolutional Networks for BiomedicalImage Segmentation

论文原文&#xff1a;U-Net: Convolutional Networks for Biomedical Image Segmentation (arxiv.org) 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔…

[笔记] Windows内核课程:保护模式《二》段寄存器介绍

文章目录 前言1、什么是段寄存器? 有哪些 ?2. 段寄存器的结构 前言 段寄存器&#xff0c;页寄存器 1、什么是段寄存器? 有哪些 ? 当我们用汇编读写某一个地址时: mov dword ptr ds:[0x123456],eax我们真正读写的地址是: ds.base 0x123456ES、CS、SS、DS、FS、GS、LDTR…

Linux和Hadoop的学习

目录 1. Linux的常用快捷键2. Hadoop集群部署问题汇总 1. Linux的常用快捷键 复制&#xff1a;CtrlshiftC 粘贴&#xff1a;CtrlshiftV TAB&#xff1a;补全命令 编写输入&#xff1a;i 退出编写&#xff1a;esc 保存并退出&#xff1a;shift&#xff1a; 2. Hadoop集群部署问…