计算二维凸包的Graham_Scan算法
凸包算法公式

凸包算法公式凸包是计算几何中的一个重要概念,而凸包算法公式则是解决相关问题的关键工具。
咱先来说说啥是凸包。
想象一下,你面前有一堆散落在地上的钉子,然后你拿一个橡皮筋把最外层的钉子圈起来,让橡皮筋形成的形状能够完全包住所有钉子,这个形状就是这堆钉子的凸包。
凸包算法有好几种,比如 Graham 扫描法、Jarvis 步进法等等。
咱就拿 Graham 扫描法来说说它涉及的公式。
Graham 扫描法里,首先要找到一个基准点。
通常找纵坐标最小的点,如果有多个这样的点,就选横坐标最小的那个。
找到这个点后,其他点就按照和这个基准点的极角大小进行排序。
这里就涉及到计算极角的公式啦。
对于两个点 A(x1, y1)和 B(x2, y2),极角θ 可以通过反正切函数来计算,公式是:θ = atan2(y2 - y1, x2 - x1)。
计算出极角后,就可以开始扫描了。
从基准点开始,依次检查相邻的三个点,如果这三个点构成的转向是逆时针的,那就保留中间那个点;如果是顺时针的,就把中间那个点去掉。
这里判断转向的公式就比较关键了。
对于三个点 A(x1, y1)、B(x2,y2)和 C(x3, y3),可以通过计算向量叉积来判断转向。
如果叉积大于 0 ,就是逆时针;小于 0 ,就是顺时针。
向量叉积的公式是:(x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1) 。
我记得之前有一次参加数学建模比赛,题目就和凸包算法有关。
当时我们小组几个人,一开始对这些公式和算法都不太熟悉,急得像热锅上的蚂蚁。
大家一起熬夜查资料、讨论,一遍遍地推导公式,尝试不同的方法。
特别是在计算极角和判断转向的时候,总是出错。
但经过不断地尝试和纠错,我们终于搞清楚了这些公式的应用,成功解决了问题,还拿到了不错的名次。
总之,凸包算法公式虽然看起来有点复杂,但只要掌握了其中的原理和规律,多做练习,就能熟练运用啦。
不管是在数学研究中,还是在实际的计算机图形学、地理信息系统等领域,凸包算法都有着广泛的应用。
凸包算法

长 江 大 学 地 球 科 学 学 院
遗留有一个问题 就是处理共线的问题 有时候我们需要凸包边上的点也考虑到 有时候却需要去掉这些点 我们通常称在凸包顶点处的点为极点 如果我们只要求保留极点而去除在边上的点 我们只需在取外侧的点的时候 碰到共线的点取最远的 相反 如果我们要保留所有在边上的点我们只需要在共线的点中取最近的 同样由于参考点的性质 所有向量之间的到角都是在180度以内 不会产生错误
我们经常关注一个点集的凸包 这也是计算几何学的一个基本问题,现在 已经有成熟的算法可以求出平面点集的凸包,凸包有着优美而实用的 性质 我们可以利用凸包把一个杂乱的点集所包含的信息进行有效的 概括、梳理。
2 Graham扫描算法(Graham Scan Algorithm)
Graham扫描算法维护一个凸壳 通过不断在凸壳中加入新的点和去除影响 凸性的点 最后形成凸包 算法主体由两部分组成 先是排序 后是扫描 分块讲解一下
void Graham(int n) { int i,top=2; Pt[n]=Pt[0]; Stack[0]=Pt[0]; Stack[1]=Pt[1]; Stack[2]=Pt[2]; for(i=3;i<=n;i++) { while(Cross(Stack[top1],Stack[top],Pt[i])<=0&&top>1) top--; Stack[++top]=Pt[i]; } }
有了向量 我们就可以选取一个最外侧的点了
长 江 大 学 地 球 科 学 学 院
利用向量 我们可以比较哪个点"更外侧" 比如点K和点I 我们利用向量JK乘以向量JI得到一个数 这 个数应该是负数 说明I比K更外侧 两个向量的比较具有传递性 所以我们可以像N个数里取 最大的数一样取出最外侧的 遍历所有点 每个点都和现有最外侧的点比较 得到新的最 外侧的点
葛立恒扫描法

葛立恒扫描法葛立恒扫描法(Graham Scan),又称凸包算法,是解决计算几何问题中的经典算法之一。
它的主要作用是计算多边形或点集的凸包,并返回凸包上的点集。
葛立恒扫描法的时间复杂度为O(nlogn),其中n是输入点集的大小。
凸包是一个简单多边形,可以包含给定点集中的所有点。
它的边界是由点集中的一些点组成的,这些点被称为凸包上的顶点。
凸包在计算几何、图形学以及计算机视觉等领域都有广泛的应用。
葛立恒扫描法的运行过程如下:1. 找到y值最小的点,并将它放在结果集中。
2. 将其余所有点按照与y值最小点的极角进行排序。
3. 对于每个点P,计算它与前两个点的极角。
如果它的角度不在逆时针方向,则将倒数第二个点从结果集中删除,然后重复此过程直到极角正确。
4. 返回结果集。
让我们来详细了解葛立恒扫描法的每个步骤。
找到y值最小的点要找到y值最小的点,我们可以遍历所有点,并找到纵坐标最小的那个。
在这里,我们使用了lambda函数来比较每个点的y值。
```python def find_lowest_point(points): lowest = min(points, key=lambda point: point[1]) return lowest ```排序接下来,我们需要将其余所有点按照与y值最小点的极角进行排序。
为此,我们需要定义一个函数来计算两点之间的极角。
在这里,我们使用了arctan2函数来计算极角。
```python def polar_angle(p1, p2=None): if p2 is None: p2 = lowest_point y_span =p1[1] - p2[1] x_span = p1[0] - p2[0] return atan2(y_span, x_span) ```然后,我们可以使用此函数来排序输入点集。
在这里,我们使用了sorted函数来排序。
```python def sort_points(points):sorted_points = sorted( points,key=cmp_to_key(lambda x,y: 1 if polar_angle(x) < polar_angle(y) else -1) ) returnsorted_points ```计算极角接下来,我们需要为每个点计算它与前两个点的极角。
探求二维凸包及其应用

探求二维凸包及其应用许瑞广,余志伟中国矿业大学(北京)资源学院(100083)E-mail :lucky_xrg@摘 要:凸包是计算几何中最普遍、最基本的一种结构,本文介绍了二维凸包的概念和性质,并介绍几种求二维凸包的方法:Gift-Wrapping 、Graham-Scan 算法,以及这几种算法的正确性和时间复杂度的分析,最后通过两个实例来简要介绍二维凸包的应用。
关键字:凸包、Gift-Wrapping 、Graham-Scan作为计算几何中第一个被深入研究的几何模型,凸包以其优美的性质带来了广泛的应用,本文将对这个几何模型进行简要的介绍。
1. 凸包的概念和性质我们首先从一个实例来引入凸包:假设你种了很多树,想用一个篱笆把所有的树都包在里面,出于经济考虑,显然这个篱笆应该是越小越好。
给出树的坐标,求出篱笆的最小周长。
如图1-1所示的篱笆是一个最小的篱笆,而这个篱笆就是这些树的凸包(Convex Hull)。
图1-1 凸包(Convex Hull)要定义凸包,首先我们来研究一下凸多边形。
定义1 凸多边形Ù整个图形在任一条边的一侧。
定义2 D 是凸多边形ÙD D x x xx ∈+∈∀2,,2121,即对于一个凸多边形任意两个内点的中点也在此图形内。
我们不仅考虑中点,还考虑所有内分点,于是有如下定义。
定义3 D 是凸多边形Ù[]D D x x xx ∈−+∈∀∈∀2121)1(,1,0,,λλλ因此定义2是定义3的一种特殊形式。
如图1-2给出了凸图形和凹图形的图示:图2-2 凸图形和凹图形设S 是平面(E 2)上的点集,用CH(S)表示点集S 的凸包,BCH(S)表示S 的凸包边界。
定义4 平面点集S 的凸包CH(S)是包含S 的最小凸集,凸包上的顶点称为极点。
点集S 的凸包是包含S 的所有凸集的并,或者CH(S)是包含S 的所有半空间的交。
二维中的半空间是半平面,它是指位于一条直线上及该线一侧的点的集合。
把点集凸包化Granham-Scan算法(使用水平序)概要

把点集凸包化Granham-Scan算法(使用水平序)#include<stdio.h>#include<string.h>#include<math.h>#include<algorithm>using nameaace std;const int M=100000+5;struct Point{double x,y;} p[M];double dis(Point A,Point B){return sqrt((B.x-A.x)*(B.x-A.x)+(B.y-A.y)*(B.y-A.y));}bool cmp(Point a,Point b){if (a.x<b.x) return true;if (a.x>b.x) return false;if (a.y<b.y) return true;return false;}double Xdet(Point A,Point B,Point C){double x1,x2,y1,y2;x1=B.x-A.x; y1=B.y-A.y; x2=C.x-A.x; y2=C.y-A.y;return x1*y2-x2*y1; //大于0在左手边,逆时针}bool bo[M];Point pp[M];int stack[M]; //from 1 to tvoid Gram_Scan(Point *p,int &n) //p从1-n,把点集土包化 n*log(n); {int i,t;sort(p+1,p+1+n,cmp);for(t=0,i=1;i<=n;i++){ //合并排序if (i>1 && p[i].x==p[i-1].x && p[i].y==p[i-1].y) continue;p[++t]=p[i];}n=t; t=0;memset(bo+1,true,n*sizeof(bo[0]));if (n>0){stack[++t]=1;bo[stack[t]]=false;}if (n>1){stack[++t]=2;bo[stack[t]]=false;}if (n>2){for(i=3;i<n;i++)if(bo[i] && Xdet(p[stack[t-1]],p[stack[t]],p[i])>=0) stack[++t]=i,bo[i]=false;else{while(t>=2&& Xdet(p[stack[t-1]],p[stack[t]],p[i])<0) bo[stack[t]]=true,t--;stack[++t]=i;bo[stack[t]]=false;}for(i=n;i>=1;i--)if (bo[i] && Xdet(p[stack[t-1]],p[stack[t]],p[i])>=0) stack[++t]=i,bo[i]=false;else{while(t>=2&&Xdet(p[stack[t-1]],p[stack[t]],p[i])<0) bo[stack[t]]=true,t--;stack[++t]=i;bo[stack[t]]=false;}t--;}for(i=1;i<=t;i++) pp[i]=p[stack[i]];memcpy(p+1,pp+1,t*sizeof(Point));n=t;}求凸点集的面积double area(Point *p,int n){double sum=0;int i;p[n+1]=p[1];for(i=1;i<=n;i++)sum+=p[i].x*p[i+1].y-p[i].y*p[i+1].x;return sum/2.0;}const double EPS=1e-9;const double maxn=1e6-1;const double PI=acos(-1.);const int M=100+5;const double offset=11213;#define zero(x) (((x)>0?(x):-(x))<EPS)struct Point{double x,y;} p[M];struct LINESEG{Point st,ed;};struct LINE{double a,b,c;};double dist(Point a,Point b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}double multiply(Point a,Point b,Point c){return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);}double dotmultiply(Point a,Point b,Point c){return (a.x-c.x)*(b.x-c.x)+(a.y-c.y)*(b.y-c.y);}bool online(LINESEG L,Point q){return fabs(multiply(L.ed,q,L.st))<EPS && (q.x-L.st.x)*(q.x-L.ed.x)<EPS && (q.y-L.st.y)*(q.y-L.ed.y)<EPS; }LINE makeline(Point p1,Point p2){LINE tl;tl.a=p2.y-p1.y; tl.b=p1.x-p2.x;tl.c=p1.y*p2.x-p1.x*p2.y;if (tl.a<EPS) tl.a=-tl.a,tl.b=-tl.b,tl.c=-tl.c;return tl;}inline double MAX(double x,double y){return x>y?x:y;}inline double MIN(double x,double y){return x<y?x:y;}bool intersect(LINESEG u,LINESEG v){return MAX(u.st.x,u.ed.x)>=MIN(v.st.x,v.ed.x)&& MAX(v.st.x,v.ed.x)>=MIN(u.st.x,u.ed.x)&& MAX(u.st.y,u.ed.y)>=MIN(v.st.y,v.ed.y)&& MAX(v.st.y,v.ed.y)>=MIN(u.st.y,u.ed.y)&& multiply(v.st,u.ed,u.st)*multiply(u.ed,v.ed,u.st)>=0&& multiply(u.st,v.ed,v.st)*multiply(v.ed,u.ed,v.st)>=0;}bool intersect_A(LINESEG u,LINESEG v){return intersect(u,v) && !online(u,v.st) && !online(u,v.ed)&& !online(v,u.st) && !online(u,v.ed);}bool intersect_L(LINESEG u,LINESEG v){return multiply(u.st,v.ed,v.st)*multiply(v.ed,u.ed,v.st)>=0;}bool intersection_line(LINE L1,LINE L2,Point &inter){ double det=L1.a*L2.b-L2.a*L1.b;if (fabs(det)<EPS) return false;inter.x=(L2.c*L1.b-L1.c*L2.b)/det;inter.y=(L2.a*L1.c-L1.a*L2.c)/det;return true;}bool intersection_lineseg(LINESEG u,LINESEG v,Point &inter){ LINE L1,L2;L1=makeline(u.st,u.ed);L2=makeline(v.st,v.ed);if (intersection_line(L1,L2,inter)) return online(u,inter) && online(v,inter);else return false;}bool intersection_LLS(LINE L1,LINESEG u,Point &inter){ LINE L2;L2=makeline(u.st,u.ed);if (intersection_line(L1,L2,inter))return online(u,inter);else return false;}int Inside(Point q,int n){Point q2;const int on_edge=0;int i=0,count;p[n]=p[0];while (i<n)for(count=0,i=0,q2.x=rand()+offset,q2.y=rand()+offset;i<n;i++)if (zero(multiply(q,p[i],p[i+1])) && (p[i].x-q.x)*(p[i+1].x-q.x)<EPS && (p[i].y-q.y)*(p[i+1].y-q.y)<EPS) return on_edge;else if (zero(multiply(q,q2,p[i]))) break;else if (multiply(q,p[i],q2)*multiply(q,p[i+1],q2)<-EPS &&multiply(p[i],q,p[i+1])*multiply(p[i],q2,p[i+1])<-EPS) count++;return count&1;}bool cmp(Point p,Point q){if (p.x<q.x) return true;if (p.x>q.x) return false;if (p.y<q.y) return true;return false;}//线段与多边形相交定义为至少有1个点在多边形内,返回true; bool LINESEG_intersect_Polygon(LINESEG LS1,int n) {LINESEG LS2;Point mid;int i;int j,top;Point stack[M];p[n]=p[000];for(i=0;i<n;i++){LS2.st=p[i]; LS2.ed=p[i+1];if (intersect_A(LS1,LS2)) return true;}top=0;stack[top++]=LS1.st;stack[top++]=LS1.ed;for(i=0;i<n;i++)if (online(LS1,p[i])) stack[top++]=p[i];sort(stack,stack+top,cmp);stack[top]=stack[0];for(j=0;j<top;j++) {mid.x=(stack[j].x+stack[j+1].x)/2;mid.y=(stack[j].y+stack[j+1].y)/2;if (Inside(mid,n)) return true;}return false;}const int M=15000;struct Line{double a,b,c;}L[M];struct Point{double x,y;} p[M],pp[M];//由两点化一般式Line LineChange(Point P1,Point P2){Line K;K.a=P2.y-P1.y;//(y2-y1)*x+(x1-x2)*y-(x1-x2)*y1-x1*(y2-y1)=0; counterclockK.b=P1.x-P2.x;K.c=-P1.x*K.a-K.b*P1.y;return k;}//求两直线交点bool GetSegcross(Line K1,Line K2,Point &pp){double det=K1.a*K2.b-K2.a*K1.b;if (fabs(det)<1e-8) return 0;pp.x=(K1.b*K2.c-K2.b*K1.c)/det;pp.y=-(K1.a*K2.c-K2.a*K1.c)/det;return 1;}//p在直线上返回0.00double p_on_line(Line K,Point p){return K.a*p.x+K.b*p.y+K.c;}//求两点的垂直平分线void MidLine(Point P1,Point P2,Line &K){K.a=2*(P1.x-P2.x);K.b=2*(P1.y-P2.y);K.c=(-K.a*(P1.x+P2.x)-K.b*(P1.y+P2.y))/2;}//求任意点对的最小距离,分治nlogn.double nearest(Point *p, int n) //p should already be sorted by x{if(n==2) return dist(p[0], p[1]);if(n==1) return INF;int m=p[n/2].x,i,j;double left,right,tmp,ret,t;left=nearest(p,n/2); right=nearest(&p[n/2],n-n/2);ret=tmp =left<right?left:right;for(i=n/2-1; i>=0 && p[i].x>m-tmp_nearest;i--)for(j=n/2; j<n && p[j].x<m+tmp_nearest;j++) {t=dist(p[i],p[j]);if(t<tmp_nearest) ret=t;}return ret;}Euler的任意四面体体积公式(已知边长求体积)已知4点坐标求体积(其中四个点的坐标分别为(x1,y1,z1),(x2,y2,z2),(x3,y3,z3),(x4,y4,z4))11111234(1/6)*.12341234x x x xVy y y yz z z z=22222222222222222222222236.2222p q n p r mpp q n q r lV qp r m q r lr+-+-+-+-=+-+-。
确定凸包上的点---Graham扫描法---java实现

确定凸包上的点---Graham扫描法---java实现假设平⾯上给出N个点,现在要求过上⾯的点把所有的点都包起来,并且周长最⼩,这些点就是凸包上的点。
确定凸包上的点有多种做法,但是只有Graham扫描时间复杂度稳定在nlog(n)上,所以就记录⼀下这个算法。
步骤:1.找出给定点中最靠近左下⽅的点2.通过这个点与其它点连线与⽔平⽅向会构成夹⾓,根据夹⾓⼤⼩进⾏由⼩到⼤排序3.根据动图中的情况,来说明扫描过程。
Graham扫描过程凸多边形的边从最左下⾓点开始,逆时针的相邻三个点P0,P1,P2构成的向量<P0,P1>,<P1,P2>的夹⾓都是⼤于0的。
也就是说,针对途中的情况,P2,P4,P5点是不可能在凸包上的。
假设P4在凸包上,那么对于P3,P4,P6来说,<P3,P4>,<P4,P6>向量的的夹⾓是⼩于0的,最后会呈现凹多边形的形态。
以P0,P1,P2,P3,P4,P5,P6来说明确定凸包点的计算⽅式:(1)使⽤栈来存储最终位于凸包上的点的位置。
(2)最开始排好顺序的三个点P0,P1,P2⼀定能够组成凸多边形,将它们压⼊栈中S[P2,P1,P0],并且P1⼀定在凸包上,现在不确定的就是P2是否真的在凸包上(有内⿁?::aru:discovertruth:: )(3)对于P3来说,我们使⽤堆栈中第⼆个元素P1,第⼀个元素P2,和扫描到的元素P3,进⾏⽐较,来确认P2到底是不是凸包上的点。
<P1,P2>,<P2,P3>向量构成的夹⾓⼩于0,说明P2⼀定不在凸包上,所以P2可以排除了,将P2从栈中弹出。
P3⼜有可能是凸包上的点,所以堆栈现在存有S[P3,P1,P0]。
(4)对于P4来说,<P1,P3>,<P3,P4>向量(<S[2],S[1]>,<S[1],当前扫描点>)构成的夹⾓是⼤于0的,所以P4有可能是凸包上的点。
凸包

readln(n,temp); for i:=1 to n do readln(x[i],y[i]); end; function ok(x,midx,y,midy:extended):longint; begin if abs(x-midx)<=zero then begin if abs(midy-y)<=zero then exit(0); if midy>y then exit(1) else exit(2); end else begin if x<midx then exit(1) else exit(2); end; end; procedure qsort(head,tail:longint); var i,j :longint; midx,midy :extended; begin i:=head; j:=tail; midx:=x[(head+tail) div 2]; midy:=y[(head+tail) div 2]; repeat while ok(x[i],midx,y[i],midy)=1 do inc(i); while ok(x[j],midx,y[j],midy)=2 do dec(j); if i<=j then begin swap(x[i],x[j]); swap(y[i],y[j]); inc(i); dec(j); end; until i>j; if i<tail then qsort(i,tail);
二.凸包问题
给定平面上的二维点集,求解其凸包。
三.算法详解(Graham's Scan)
1. 在所有点中选取 y 坐标最小的一点 H,当作基点。如果存在多个点的 y 坐标都为最小值,则 选取 x 坐标最小的一点。坐标相同的点应排除。然后按照其它各点 p 和基点构成的向量<H,p> 与 x 轴的夹角进行排序,夹角由大至小进行顺时针扫描,反之则进行逆时针扫描。实现中无需 求得夹角,只需根据向量的内积公式求出向量的模即可。以下图为例,基点为 H,根据夹角由小 至大排序后依次为 H,K,C,D,L,F,G,E,I,B,A,J。下面进行逆时针扫描。
graham scan算法 原理

Graham Scan算法一、概述Graham Scan算法是一种用于计算凸包的算法,它可以在给定二维平面上的一组点时,找到这些点形成的凸包。
凸包是包围点集的最小凸多边形,它的边界上的点不弯曲向内。
二、算法原理Graham Scan算法采用了一种基于极角排序的方法来求解凸包,其基本思路如下:1.找到y坐标最小的点P0,将P0作为凸包的起点。
2.将其他点按照与P0的极角进行逆时针排序。
3.遍历排序后的点集,如果凸包的点个数小于2,或者遍历点与前两个点的构成的两条线段的转向(顺时针或逆时针)满足逆时针,则将遍历点添加到凸包中;否则,将凸包的最后一个点移除,再添加遍历点。
4.最终的凸包即为所有添加后剩下的点集。
三、算法实现步骤下面将详细介绍Graham Scan算法的实现步骤:1. 寻找起点先确定凸包的起点,即y坐标最小的点P0。
可以通过比较每个点的y坐标找到最小的那个点。
如果有多个点的y坐标相等,选择其中x坐标最小的点。
2. 极角排序对于起点P0之外的其他点,计算它们与P0的极角,并按照极角进行逆时针排序。
计算极角时,可以使用两点之间的斜率来表示,斜率越大则两点之间的角度越小。
3. 构建凸包从排好序的点集中依次取出每个点Pi,将其添加到凸包中。
首先,检查凸包中的点个数是否小于2。
当凸包中的点个数小于2时,直接将Pi 添加到凸包中。
然后,检查凸包中的最后两个点Pi-1和Pi-2构成的线段的转向。
当这两个点以及Pi构成的三个点满足逆时针时,将Pi添加到凸包中。
反之,将凸包中的最后一个点移除,再将Pi添加到凸包中。
4. 输出凸包最终,凸包中包含了输入点集形成的凸多边形。
遍历凸包中的点,按顺序输出它们的坐标,即可得到凸包。
四、算法复杂度分析时间复杂度1.寻找起点:需要遍历所有点来找到起点,时间复杂度为O(n)。
2.极角排序:对n-1个点进行排序,时间复杂度为O(nlogn)。
3.构建凸包:需要遍历所有点,时间复杂度为O(n)。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
计算二维凸包的Graham_Scan算法
凸包的概念:
点集Q的凸包(convex hull)是指一个最小凸多边形,满足Q中的点或者在多边形边上或者在其内。
下图中由红色线段表示的多边形就是点集Q={p0,p1, (12)
的凸包。
凸包的求法:
现在已经证明了凸包算法的时间复杂度下界是O(n*logn),但是当凸包的顶点数h也被考虑进去的话,Krikpatrick和Seidel的剪枝搜索算法可以达到
O(n*logh),在渐进意义下达到最优。
最常用的凸包算法是Graham扫描法和Jarvis 步进法。
本文只简单介绍一下Graham扫描法,其正确性的证明和Jarvis步进法的过程大家可以参考《算法导论》。
对于一个有三个或以上点的点集Q,Graham扫描法的过程如下:
令p0为Q中Y-X坐标排序下最小的点;
设<p1,p2,...pm>为对其余点按以p0为中心的极角逆时针排序所得的点集(如果有多个点有相同的极角,除了距p0最远的点外全部移除;
压p0进栈S;
压p1进栈S;
压p2进栈S;
for i ←3 to m
{
do while{由S的栈顶元素的下一个元素、S的栈顶元素以及pi构成的折线段不拐向左侧}对S弹栈;
压pi进栈S;
}
return S;
此过程执行后,栈S由底至顶的元素就是Q的凸包顶点按逆时针排列的点序列。
需要注意的是,我们对点按极角逆时针排序时,并不需要真正求出极角,只需要求出任意两点的次序就可以了。
而这个步骤可以用前述的矢量叉积性质实现。