当前位置: 首页 > news >正文

Jarvis 算法

Jarvis 算法,也被称为包装算法(Gift Wrapping Algorithm),主要用于解决二维平面上的凸包问题。凸包问题是指在一个二维平面上给定一组点,找出能够包含所有这些点的最小凸多边形。下面将从算法原理、代码实现、复杂度分析等方面对 Jarvis 算法进行详细解析。

算法原理

Jarvis 算法的核心思想是从最左边的点开始,通过不断寻找相对于当前点具有最小极角的点,逐步构建凸包。具体步骤如下:

  1. 找到最左边的点:在所有给定的点中,找到 (x) 坐标最小的点。如果有多个点的 (x) 坐标相同,则选择 (y) 坐标最小的点。这个点一定是凸包上的一个点。
  2. 初始化当前点:将最左边的点作为当前点。
  3. 寻找下一个凸包点:从当前点出发,遍历所有其他点,计算每个点相对于当前点的极角。选择极角最小的点作为下一个凸包点。
  4. 更新当前点:将找到的下一个凸包点作为新的当前点。
  5. 重复步骤 3 和 4:直到回到最开始的点,此时凸包构建完成。

代码实现

以下是使用 Python 实现的 Jarvis 算法代码:

def orientation(p, q, r):"""计算三个点的方向:param p: 第一个点:param q: 第二个点:param r: 第三个点:return: 0 表示共线,1 表示顺时针,2 表示逆时针"""val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1])if val == 0:return 0  # 共线elif val > 0:return 1  # 顺时针else:return 2  # 逆时针def jarvis(points):"""使用 Jarvis 算法计算凸包:param points: 二维平面上的点集:return: 凸包上的点集"""n = len(points)if n < 3:return points# 找到最左边的点l = 0for i in range(1, n):if points[i][0] < points[l][0]:l = ihull = []p = lq = 0while True:hull.append(points[p])q = (p + 1) % nfor i in range(n):if orientation(points[p], points[i], points[q]) == 2:q = ip = qif p == l:breakreturn hull# 测试
points = [(0, 3), (2, 2), (1, 1), (2, 1), (3, 0), (0, 0), (3, 3)]
hull = jarvis(points)
print("凸包上的点:", hull)

代码解释

  1. orientation 函数:该函数用于计算三个点的方向。通过计算向量叉积的符号来判断三个点的相对位置,返回值为 0 表示共线,1 表示顺时针,2 表示逆时针。
  2. jarvis 函数:该函数实现了 Jarvis 算法的主要逻辑。首先找到最左边的点,然后通过不断寻找下一个凸包点,直到回到最开始的点。
  3. 主程序:定义了一组测试点,调用 jarvis 函数计算凸包,并输出凸包上的点。

复杂度分析

  • 时间复杂度O(nh)O(nh)O(nh),其中 nnn 是点的总数,hhh 是凸包上的点的数量。在最坏情况下,hhh 可能等于 nnn,此时时间复杂度为 O(n2)O(n^2)O(n2)
  • 空间复杂度O(h)O(h)O(h),主要用于存储凸包上的点。

优缺点

  • 优点:算法简单易懂,实现方便,适用于小规模数据集。
  • 缺点:时间复杂度较高,在处理大规模数据集时效率较低。

其他要点

1、代码块解释
while True:
hull.append (points [p])
q = (p + 1) % n
for i in range (n):
if orientation (points [p], points [i], points [q]) == 2:
q = i
p = q
if p == l:
break

这段代码是 Jarvis 算法核心部分,其主要功能是不断寻找凸包上的点,直到形成一个完整的凸包。下面逐行对代码进行详细解释:

1.1 整体功能概述

在 Jarvis 算法中,我们从最左边的点开始,不断寻找相对于当前点具有最小极角的点作为下一个凸包上的点,重复这个过程,直到回到起始点,从而构建出整个凸包。这段代码就是实现这个过程的具体逻辑。

1.2代码逐行解释
while True:
  • 这是一个无限循环,用于不断寻找凸包上的点,直到满足特定条件跳出循环。
    hull.append(points[p])
  • hull 是一个列表,用于存储凸包上的点。points[p] 表示当前正在处理的点,将其添加到 hull 列表中,意味着将该点确定为凸包上的一个点。
    q = (p + 1) % n
  • n 是点集 points 的长度。(p + 1) % n 用于计算下一个候选点的索引。使用取模运算 % 是为了确保索引不会超出点集的范围,当 p 达到 n - 1 时,(p + 1) % n 会回到 0,形成一个循环。
    for i in range(n):
  • 这是一个遍历所有点的循环,目的是从所有点中找到相对于当前点 points[p] 具有最小极角的点。
        if orientation(points[p], points[i], points[q]) == 2:
  • orientation 函数用于判断三个点的方向关系,返回值为 0 表示共线,1 表示顺时针,2 表示逆时针。
  • 这里的判断条件 orientation(points[p], points[i], points[q]) == 2 表示如果点 points[i] 相对于点 points[p]points[q] 是逆时针方向,说明 points[i]points[q] 更适合作为下一个凸包上的点。
 	q = i
  • 如果满足上述条件,将 q 的值更新为 i,即把 points[i] 作为新的候选下一个凸包点。
    p = q
  • 循环结束后,将 p 的值更新为 q,意味着将找到的下一个凸包点作为新的当前点,继续进行下一轮的寻找。
    if p == l:break
  • l 是最开始找到的最左边的点的索引。当 p 再次等于 l 时,说明已经回到了起始点,此时凸包构建完成,使用 break 语句跳出无限循环。
总结

这段代码通过不断循环,从当前点出发,遍历所有点,找到相对于当前点具有最小极角的点作为下一个凸包点,直到回到起始点,从而构建出完整的凸包。

2、为什么逆时针方向说明points[i] 比 points[q] 更适合作为下一个凸包上的点?

要理解为什么当点 points[i] 相对于点 points[p]points[q] 是逆时针方向时,points[i]points[q] 更适合作为下一个凸包上的点,我们需要从凸包的定义和几何性质入手。

凸包的定义

凸包是包含给定点集的最小凸多边形。凸多边形的一个重要性质是,对于多边形上的任意一条边,多边形上的所有其他点都位于这条边的同一侧。也就是说,沿着凸包的边界顺时针或逆时针遍历,相邻的三条边之间的转向总是保持一致(要么都是顺时针,要么都是逆时针)。

算法寻找凸包点的原理

在 Jarvis 算法中,我们从一个已知在凸包上的点(最左边的点)开始,不断寻找下一个凸包上的点。在每一轮迭代中,我们需要找到相对于当前点 points[p] 能使凸包保持凸性的下一个点。

逆时针方向与凸包构建的关系

假设我们已经确定了当前凸包上的一个点 points[p],并且有一个候选的下一个点 points[q]。现在我们遍历所有其他点 points[i],并通过 orientation 函数判断它们相对于 points[p]points[q] 的方向。

  • 逆时针方向的几何意义:当 orientation(points[p], points[i], points[q]) == 2 时,说明从 points[p]points[q] 再到 points[i] 是逆时针方向。从几何角度看,这意味着 points[i] 在由 points[p]points[q] 所确定的直线的“外侧”。

  • 凸包构建的要求:为了构建一个凸包,我们希望每一步选择的点都能使凸包向外扩展,而不是向内凹陷。如果选择的点使得新的边向内凹陷,那么就不满足凸包的定义了。

  • 比较 points[i]points[q]:当 points[i] 相对于 points[p]points[q] 是逆时针方向时,选择 points[i] 作为下一个凸包点可以保证凸包继续向外扩展,保持凸性。而如果选择 points[q],可能会导致凸包出现向内凹陷的情况。

示例说明

假设我们有三个点 A(对应 points[p])、B(对应 points[q])和 C(对应 points[i])。如果从 AB 再到 C 是逆时针方向,那么当我们构建凸包时,选择 C 作为 A 的下一个相邻点,能够让凸包的边界向外扩展,形成一个更大的凸多边形。相反,如果选择 B,可能会使凸包在这个位置向内弯曲,不符合凸包的定义。

综上所述,当点 points[i] 相对于点 points[p]points[q] 是逆时针方向时,points[i]points[q] 更适合作为下一个凸包上的点,因为这样可以保证凸包的凸性,使凸包不断向外扩展。

3、顺时针方向为什么不适合作为下一个凸包上的点?

在 Jarvis 算法构建凸包的过程中,顺时针方向的点通常不适合作为下一个凸包上的点,这与凸包的定义、几何性质以及算法的目标紧密相关,下面为你详细解释:

顺时针方向不符合凸包构建要求
  • 产生凹陷情况:假设当前已经确定了凸包上的一个点 (P)(对应代码中的 points[p]),并且有一个候选的下一个点 (Q)(对应 points[q])。当我们遍历到另一个点 (R)(对应 points[i]),如果从 (P) 到 (Q) 再到 (R) 是顺时针方向,那么选择 (Q) 作为 (P) 的下一个相邻点,会使得凸包在这个位置向内凹陷。
  • 例如,想象一个简单的场景,有三个点 (A)、(B)、(C),若按照 (A - B - C) 是顺时针顺序,当以 (A) 为起点构建凸包时,如果选择 (B) 作为下一个点,那么 (C) 就会位于 (A) 和 (B) 所构成线段的“内侧”,这样形成的多边形就不是凸多边形了,不符合凸包的定义。
  • 破坏凸性:凸包要求其边界是向外扩展的,每一步选择的点都应该使凸包的范围不断扩大,且保持整体的凸性。顺时针方向的点会破坏这种凸性,导致构建出的多边形无法满足凸包的条件。
Jarvis 算法的目标和逻辑
  • 目标:Jarvis 算法的目标是逐步构建一个完整的凸包,从一个已知在凸包上的点(通常是最左边的点)开始,不断寻找下一个能使凸包保持凸性的点。
  • 逻辑:通过不断寻找相对于当前点具有最小极角(在逆时针方向上)的点作为下一个凸包点,算法能够保证每一步都朝着正确的方向扩展凸包。如果选择顺时针方向的点,就会与算法的这种扩展逻辑相悖,无法正确构建出凸包。

综上所述,在 Jarvis 算法中,顺时针方向的点不适合作为下一个凸包上的点,因为它会破坏凸包的凸性,不符合凸包的定义和算法的构建逻辑。

http://www.dtcms.com/a/430834.html

相关文章:

  • [Linux基础——Lesson6.编译器gcc/g++以及动静态库的认识]
  • 【ROS2】快速创建一个包
  • Markdown——2.LaTeX数学公式
  • 网站系统建设合同范本网站建设相关技术
  • 做网站准备的资料竞猜世界杯
  • Python 开发工具,最新2025 PyCharm 使用
  • 新公司注册在哪个网站p2p网站建设教程
  • 2008 年真题配套词汇单词笔记(考研真相)
  • 增强版 bash “zsh“
  • 图数据库:基于历史学科的全球历史知识图谱构建,使用Neo4j图数据库实现中国历史与全球历史的关联查询。
  • conda建立虚拟环境,并在jupyter notebook中显示,查看与已安装包是否冲突
  • 美食网站策划书新网站如何让百度收录
  • [创业之路-642]:新质生产力、硬科技与数字经济深度融合
  • 今日分享 浮点数二分
  • DataTool.vip官网入口 - 多平台视频与音频免费下载器工具
  • 文心雕龙:DIFY 工作流驱动的Word自动化生成与规范排版方案
  • asp sql做学生信息网站中国建设银行演示网站
  • windows10 系统添加第二块硬盘(解决硬盘盘符丢失问题)
  • java-代码随想录第48天|739. 每日温度、496.下一个更大元素 I、503.下一个更大元素II
  • 在嘉立创的泰山派上也能运行Easysearch
  • JSP 点击量统计
  • 应用网站如何做外贸网站建设哪里做得好
  • Kubernetes证书管理实战:cert-manager部署与CRD导出
  • [Java]PTA: jmu-Java-02基本语法-08-ArrayList入门
  • 网站建设背景及目的搜索优化的培训免费咨询
  • 2012 年真题配套词汇单词笔记(考研真相)
  • Ubuntu20.04 按照飞浆paddle 3.2遇到的问题
  • 网站建设推荐郑国华做网站ps图片都是多大
  • 探索 Docker/K8s 部署 MySQL 的创新实践与优化技巧
  • 线程属性的相关设置详解