回顾凸包构造算法:极点法、极边法和增量构造法,其复杂度分别为O(n^4)、O(n^3)和O(n^2),效率经过优化已经大大提高了。接下来引入一种新的算法——Jarvis March,其复杂度也是O(n^2),但是相较于增量构造在最好情况下效率是较高的。

一、选择排序

依旧是先回顾一个经典算法:选择排序(selection sort)。排序过程可以归结为下图:

对比插入排序,可以发现sorted部分变成了从后向前扩张。算法的整体思路依然是增量式的,每次选取unsorted部分中的最大元素,和sorted部分前一个元素交换,重复上述过程完成sorted部分的扩张最终使得序列有序。

和插入排序每次随便从unsorted部分选取元素不同,选择排序每次选取出的unsorted最大元素放在sorted前一个位置上,也就意味着整个unsorted部分必然不会超过sorted部分。从算法整体框架考虑,每次我们都是维护一个局部解(也就是sorted部分),然后从尚未处理的部分(也就是unsorted部分)找到一个与当前局部解“紧密相关的元素”(相当于选取的最大元素)。这个思想为解决凸包问题带来了新思路。

二、策略

再来考虑为何极边法复杂度高达O(n^3)。实际上我们要对点集中所有边进行遍历,这需要n^2复杂度,然后对每个边进行鉴别,又需要n复杂度,因此总体复杂度高达O(n^3)。那么该如何改进呢?这就可以运用选择排序的思想:将下一个要查找的边缩小到一个小范围,而非遍历所有边。

先对算法的大致过程有直观的认识(标识为:已找到极边数/所有极边数):

首先从任何一个极点(后面说明如何找到这个点)开始(图中0/5),然后找到一条以这个极点为端点的极边(1/5)。接着沿着极边另一个端点(endpoint)出发,再找出下一条极边(2/5)。如此反复操作,最终会找到一条以最初极点为endpoint的极边,得到一个封闭的环,凸包也构造完成。凸包构造过程类似于选择排序中sorted不断向前扩展一样,不断扩展局部解,最后得到问题最终解。

凸包构造的问题由此分解为一个个子问题:如何从endpoint出发找到下一条极边。

三、继续to left test

考虑以下一般情况:

我们从极点o开始寻找极边,假设当前找到的极边是ik,接下来要做的工作是找到从k出发的另一条极边ks,即找到极点s。

显然,s来自于其他那些尚未处理的点中,那么s与其他点相比有什么特征?观察发现,ik作为一条极边,它的右侧肯定都是空的,所有其他点都在ik左侧。画出k与其他候选点的有向直线,例如下图中的ks,kt:

注意图中红色标出的角度,可以看出ks与ik的夹角比kt小,也就是ks比kt相较于ik偏左的角度更小。实际上ks偏左的角度比其他任何从k出发的边都小,这就是s点的判定依据。

这样就找到了从其余点中选择s点的思路:任选两个点,从k出发过这两点做有向边,看哪个偏左的角度更小就留下,另一点丢弃。然后再拿一点与留下的点比较,反复这个过程,最终留下的就是要找的s点。

问题至此转化为:如何比较两条有向边(例如ks和kt)相较于另一有向直线(例如ik)谁偏左的角度更小。

当然可以通过计算三角函数的方法来比较,这是最直观的数学思维。但是这样计算十分复杂,更重要的是引入了误差。这时候又要使用to left test这个基础方法来解决问题了。

具体做法就是以在ks和kr中以任意个为基准(如以ks为基准),对另一点(如t)做to left test。上图点t和有向边ks的to left test结果为true,t在ks左边,因此ks偏左的角度更小,舍弃点t。

类比选择排序来理解,sorted部分就相当于已得到的极边(从极点o开始到ik的首尾相连的极边),unsorted部分相当于其余点,从unsorted部分取出极大值就相当于找到点s——能构成最小偏角的点。选择排序中的选择过程需要比较元素大小,就要由一种比较器完成,而上述比较偏角的过程也可以抽象为一种比较器的操作。构造凸包的算法框架与选择排序相同,只是比较器替换为to left test而已。

//此处只是考虑一般情况,一些特殊细节未进行处理。例如在st上有s和s'两点,这两点的取舍问题未考虑。当然为了理解算法整体框架忽略特殊情况是很必要的。

然后考虑一个细节问题,也就是上文提到的算法最开始第一个极点如何确定。任何一个极点都可以使用,我们没必要去计算出哪个点是极点。可以选取y坐标最小的点,也就是最低点,在没有退化的情况下,这个点一定是一个极点。如果情况退化,有多个最低点(如例图中所示),我们就去选x坐标最小的那个点,也就是最左边的点即可。这种方法选出的点称为lowest-then-leftmost point(LTL)。注意选取的规则的先后顺序,先选lowest,若点不唯一再选leftmost。

四、Jarvis March

类比选择排序的过程,我们得到的凸包构造算法就是Jarvis March算法,又称gift wrapping算法(算法过程如包装礼物一样)。接下来看算法具体实现方法。

bool ToLeft(Point p, Point q, Point s)
{int area2 =   p.x * q.y - p.y * q.x + q.x * s.y - q.y * s.x+ s.x * p.y - s.y * p.x;return area2 > 0; //左侧为真
}int ltl(Point S[], int n)
{int LTL = 0;for (int k = 1; k < n; k++)if (S[k].y < S[LTL].y ||(S[k].y == S[LTL].y &&S[k].x < S[LTL].x))LTL = K;return LTL;
}void Jarvis(Point S[], int n)
{for (int = 0; k < n; k++)S[k].extreme = false;  //首先将所有点标记为非极点int LTL = ltl(s, n); //找到LTLint k = LTL;            //将LTL作为第一个极点do{S[k].extreme = true;   //判定为极点int s = -1;//选取下一个极点,每次比较两个点s和t,//做点t和有向边ks的to left test,最终找到sfor (int t = 0; t < n; t++)if (t != k && t != s &&   //除了k和s外每个点(s == -1 || !ToLeft(P[k], P[s], P[t]))) // s = t; //如果t在s右边S[k].succ = s;    //k点的后继为sk = s;    //s变为下一次查找的起点} while (LTL != k)
}

最后分析Jarvis March算法相较于增量构造法的优势。二者都是O(n^2)的复杂度,Jarvis March算法的优势在于其的“输出敏感性(output sensitive)”。考虑点集S,共有n个点,来构造S上的凸包。

何为“输出敏感性”?Jarvis March算法每次新加入一条边都会耗费n的复杂度,但是构造过程一共会加入的边数往往比n少。如下图(设n = 7):

在非退化为共线的前提下,最好情况为只加入3条边(复杂度为O(3n)),最坏情况为所有点都是极点,加入n-1条边(复杂度为O(n^2))。实际情况中最坏情况出现的几率很小,我们引入一个指标h来衡量凸包的极边数(the size of convex hull):

h = |CH(S)|

Jarvis March算法算法的复杂度更准确的表示为O(nh)。h又由最终输出结果,即凸包本身来决定,输出结果决定了构造过程的复杂度,这就是所谓的“输出敏感性”。这种类型的算法又被称为output sensitive algorithm。这种特性在其它凸包算法中也会体现。

本文是学堂在线课程《计算几何》的笔记,帮助理解和记录思考过程,不够严谨请见谅。

计算几何入门 1.4:凸包的构造——Jarvis March算法相关推荐

  1. 计算几何入门 1.6:凸包的构造——Graham Scan算法

    上文简要分析出了凸包构造问题算法的下界:O(nlogn),在此就引入一种下界意义上最优的算法:Graham Scan算法.这种算法可以保证在最坏情况下时间复杂度也不超过nlogn.我们先大致了解一下算 ...

  2. Convex Hull:O(h*n)算法 Jarvis March

    课程:计算几何 书籍:计算几何:算法与应用 Jarvis March算法也是一种递增式的思路.以极边的一个端点为起点,来查找另一条极边.以此进行下去,最后构成一个环路时(极点的末端等于最初的起始端点) ...

  3. 计算几何入门 1.3:凸包的构造——增量构造法

    极点法和极边法的复杂度分别为O(n^4)和O(n^3),当点集S的规模稍大时就难以适用了.为了满足实际需要必须寻找更高效的算法来构造凸包. 一.减治 在引入新算法之前首先来回顾一下经典的算法思想:减治 ...

  4. 计算几何入门 1.1:凸包的概念

    一.什么是计算几何: 计算几何学(computational geometry)发展于二十世纪七十年代末,是一个正在飞速发展的新型学科.作为一个计算机算法类学科的分支,计算几何讨论更多的是计算而非几何 ...

  5. POJ 计算几何入门题目推荐(转)

    POJ 计算几何入门题目推荐(转)       其实也谈不上推荐,只是自己做过的题目而已,甚至有的题目尚未AC,让在挣扎中.之所以推荐计算几何题,是因为,本人感觉ACM各种算法中计算几何算是比较实际的 ...

  6. POJ 计算几何入门题目推荐

      其实也谈不上推荐,只是自己做过的题目而已,甚至有的题目尚未AC,让在挣扎中.之所以推荐计算几何题,是因为,本人感觉ACM各种算法中计算几何算是比较实际的算法,在很多领域有着重要的用途(例如本人的专 ...

  7. [Z]POJ 计算几何入门题目推荐[转PKKJ]

    http://www.cnblogs.com/eric-blog/archive/2011/05/31/2064785.html http://hi.baidu.com/novosbirsk/blog ...

  8. 杭电ACM-LCY算法进阶培训班-专题训练(计算几何入门)

    杭电ACM-LCY算法进阶培训班-专题训练(计算几何入门) 传送门 杭电ACM-LCY算法进阶培训班-专题训练(计算几何入门) Shape of HDU Problem Description Inp ...

  9. 零基础入门深度学习(3) - 神经网络和反向传播算法

    无论即将到来的是大数据时代还是人工智能时代,亦或是传统行业使用人工智能在云上处理大数据的时代,作为一个有理想有追求的程序员,不懂深度学习(Deep Learning)这个超热的技术,会不会感觉马上就o ...

最新文章

  1. Java 8 失宠!开发人员向 Java 11 转移...
  2. 华为nova5iotg功能使用_如果你的手机存在NFC功能,一定要尝试一下这些操作,体验超级棒...
  3. gantt project 使用
  4. 第五章--预处理理论
  5. 2013年7月28日web前端学习笔记-------head相关标签应用
  6. java实现HTTP请求的三种方式
  7. 【转】DICOM通信 - PDU数据包(2)
  8. Markdown语法、相关警告配置设置——持续更新
  9. 微软开源软件特征源码分析工具 Application Inspector
  10. Linux多进程的应用
  11. php能反序列化js的吗,javascript – 如何在node.js中反序列化PHP会话?
  12. 问题解决之--无法识别的属性“targetFramework”。请注意属性名称区分大小写。
  13. excel报表管理系统mysql_比较电子表格软件Excel与数据库管理系统的优缺点
  14. 图片怎样把背景去掉?怎么把图片背景透明?
  15. 京瓷1800打印机扫描步骤_京瓷复印机扫描设置方法京瓷复印机扫描到电脑设置...
  16. matlab2012工具栏在哪里,Word2010和2013工具在哪里及自定工具栏
  17. 软考-网络工程师-下午考试知识点
  18. 斯坦福大学公开课:iOS8开发 第一课:课务,iOS8概述学习笔记
  19. “ji32k7au4a83”是一个弱密码?
  20. 抖音短链接v.douyin.com生成方法

热门文章

  1. 深入浅出 - Android系统移植与平台开发(十)- Android编译系统与定制Android平台系统
  2. MATLAB与FPGA数字信号处理(数字滤波器设计)、数字IC、无线通信、图像处理、信道编码系列
  3. 告警流量分析:Cobalt Strike(默认实验文)
  4. 潇洒郎: 解决联想电脑Y430p 一碰触摸板就蓝屏
  5. [杨可桢]机械设计基础题库 机械设计基础习题 2022机械设计基础考试题答案 杨可桢《机械设计基础》(第7版)笔记和课后习题(含考研真题)详解
  6. 可怕,GPT-3论坛跟帖灌水一周无人发现!专挑热搜,秒秒钟长文
  7. 如何查看路由器的宽带连接密码
  8. c 语言怎么实现可视化编程,自定义编程语言的实现
  9. 每日加瓦,终成栋房4-final、内部类、权限修饰符
  10. leetcode:雪糕的最大数量