2D凸包算法(二):Graham's Scan

Graham’s Scan 图示

在这里插入图片描述
Graham’s Scan 是先进行排序,然后再进行包围点,中间用到了栈,最为节点存储,这样就不必遍历所有点的方式来寻找最外围的点。

  • 时间复杂度:O(NlogN) ,主要取决于排序的时间。
    (其中寻找起点的时间 O(N) 。加上排序的时间 O(NlogN) 。加上包围的时间 O(N) :总共前进 N 次,最多倒退 N 次,共为 2N 次。)
具体思想:
  1. 排序,根据某个坐标轴为主进行排序
  2. 在边界上找到一个点作为起点
  3. 寻找附件2个点,将3个点依次压入栈中
  4. 对栈顶的2个点和点集中的其他点进行方向测试(可以利用叉积运算来判断)
  5. 如果是反方向的,则出栈,重复第4步
  6. 如果是正方向的,则进栈,重复第4步
  7. 直到所有点构成一个完整回路

Graham’s Scan 代码

long long int orientation(Point p, Point q, Point r) 
{ 
	double val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); 
	if (val == 0) return 0; 
	return (val > 0)? 1: 2; 
} 

int compare(const void *vp1, const void *vp2) 
{ 
	Point *p1 = (Point *)vp1; 
	Point *p2 = (Point *)vp2; 

	long long int o = orientation(p0, *p1, *p2); 
	if (o == 0) 
		return (distSq(p0, *p2) >= distSq(p0, *p1))? -1 : 1; 
	
	return (o == 2)? -1: 1; 
} 


vpdd convexHull(Point points[], long long int n) 
{ 
	long long int ymin = points[0].y, min = 0; 
	for (long long int i = 1; i < n; i++) 
	{ 
		long long int y = points[i].y; 

		if ((y < ymin) || (ymin == y && 
			points[i].x < points[min].x)) 
			ymin = points[i].y, min = i; 
	} 

	swap(points[0], points[min]); 

	p0 = points[0]; 
	qsort(&points[1], n-1, sizeof(Point), compare); 
	vpdd output;
	
	long long int m = 1; 
	for (long long int i=1; i<n; i++) 
	{ 
		while (i < n-1 && orientation(p0, points[i], points[i+1]) == 0) 
			i++; 
		points[m] = points[i]; 
		m++;
	} 
	if (m < 3){ return output;
	} 
	stack<Point> S; 
	S.push(points[0]); 
	S.push(points[1]); 
	S.push(points[2]); 

	for (int i = 3; i < m; i++) 
	{ 
		while (orientation(nextToTop(S), S.top(), points[i]) != 2) 
			S.pop(); 
		S.push(points[i]); 
	} 
	// Now stack has the output points, print contents of stack 
	
	//int i=0;
	long long int len=S.size();
	pair <double,double> Pair1 ; 
	while (!S.empty()) 
	{ 
		Point p = S.top();
		Pair1.first=p.x;
		Pair1.second=p.y; 
		//cout << p.x << ", " << p.y << endl;
		output.push_back(Pair1) ;
		S.pop(); 
	} 
	//sort(output.begin(),output.end());
	/*for(int i=0;i<len;i++){
		cout << output[i].first << ", " << output[i].second << endl;
		
	}*/
	return output;  

} 
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值