前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >凸包问题之GrahamScan解法

凸包问题之GrahamScan解法

作者头像
chain
发布2018-08-02 14:55:08
6730
发布2018-08-02 14:55:08
举报

继上一篇凸包问题的蛮力解法,本篇将介绍凸包问题的GrahamScan解法。

首先了解一下GrahamScan解法的原理:

当沿着Convex hull逆时针漫游时,总是向左转在极坐标系下按照极角大小排列,然后逆时针方向漫游点集,去除非Convex hull顶点(非左 转点)。

第一步

这里P0是极坐标的中心,在编程的时候,经常就是选择y坐标最低的点

第二步:

这样就建立起了所有点到P0的极坐标

第三步:

这里首先选择三个点压栈,这三个点肯定构成的是非右转关系

看P3

可以发现P3和P2P1构成右转关系,因此考虑把P2从凸包点中排除,然后把P3加入到凸包栈中,继续向前探进

第四步:

这里P3P4P5都不构成右转,因此都放入到凸包栈中,

第五步:

P6P5P4构成右转关系,因此需要删除P5,加入P6,

P7P6P4构成右转关系,因此删除P6,加入P7,P7P4P3构成非右转关系,删除P4。。。。。。。

知道所有点都遍历完

第七步:

上图构成的就是凸包了(包括P0)

通过上面的几个步骤相信大家已经领悟到其中的奥妙了,下面贴出主要代码:

代码语言:javascript
复制
/* 计算凸包 */
void CalculateConvexHull2(struct Point *pArray,struct Polar *prArray,int length)
{
	//初始化
	InitializePolarCoordinates(pArray,prArray,length);

	struct Polar *start=prArray;

	//栈中最上面的两个点 
	struct Polar *p1=NULL,*p2=NULL;
	top=0;
	
	//最小的三个点压栈

	stack[top++]=start++;
	stack[top++]=start++;
	stack[top++]=start++;	

	while(start!=prArray+length) {
		//获取p1和p2
		p2=stack[top-1];
		p1=stack[top-2];

		//右转,弹出p2,压入p1
		while(IsRightTuring(start->p,p2->p,p1->p) > 0 ) {
			if(top<=2)
				break;
			top--;
			p2=stack[top-1];
			p1=stack[top-2];
		}

		//压入新的点
		stack[top++]=start++;
	}
	
}

/* 打印凸包点 */
void PrintConvexHull2(struct Point *pArray,struct Polar *prArray,int &length)
{
	CalculateConvexHull2(pArray,prArray,length);

	using std::cout;
	using std::endl;

	for(int i=0;i<top;i++) {
		cout<<stack[i]->p->x<<","<<stack[i]->p->y<<endl;
	}
	//更新长度
	length=top;
}

其中Point就是直角坐标系的点,而Polar是对应的极坐标系的点,因此我们还需要建立极坐标系,建立极坐标系的关键就是找极坐标中心

下面贴而出相关代码:

代码语言:javascript
复制
/* 排序选择Y轴最低的坐标点作为极坐标中心 */
static struct Point ChooseCentroid(struct Point *pArray,int length)
{
	qsort(pArray,length,sizeof(struct Point),PointYCompare);
	return pArray[0];
}
代码语言:javascript
复制
/* 直角坐标转化为极坐标 */
void PointToPolar(struct Point * ptArray,struct Polar *prArray,int length,struct Point centroid)
{
	for(int i=0;i<length;i++) {
		//在极坐标横轴上
		if(ptArray[i].y==centroid.y) {
			if(ptArray[i].x>=centroid.x)
				prArray[i].angle=0;
			else
				prArray[i].angle=180;
		}
		//90度
		else if(ptArray[i].x==centroid.x)
			prArray[i].angle=90;
		//其他
		else
			prArray[i].angle=arctan(ptArray[i],centroid);

		//长度暂时不用

		//指针指向
		prArray[i].p=&ptArray[i];
	}
}
代码语言:javascript
复制
/* 初始化极坐标系 */
static void InitializePolarCoordinates(struct Point *pArray,struct Polar *prArray,int length)
{
	//找极坐标中心
	struct Point centroid=ChooseCentroid(pArray,length);

	//直角坐标转化为极坐标
	PointToPolar(pArray,prArray,length,centroid);

	//极坐标排序
	PolarQuickSort(prArray,0,length-1);
}

大家可以参考上述代码,其他非关键函数相信大家都能补全,就不再贴出了。

下一篇将介绍凸包问题的GrahamScan和分治的结合算法。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2014年12月07日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档