凸包算法-------Graham扫描法

在网络上关于凸包解法多种多样,讲的也非常的不错,可以参考一下这篇博客,但是还是想用自己的话去描述一遍,以加深一下印象。

常见的解法有:

  • 穷举法(蛮力法)
  • 分治法
  • Jarvis步进法
  • Graham扫描法
  • Melkman算法

本文主要讲一下Graham扫描法的步骤以及实现,先借一张动图来说明一下Graham扫描的算法的流程。

 è¿éåå¾çæè¿°

算法流程

  1. 找到相对左下角的点P0,为什么叫相对,因为我这里是先找到y轴最小的点,如果有相同,则选择X轴最小的点;
  2. 计算所有的点与P0的极角的大小,并由小到大的排序,如上面的动图所示排序好的顺序;
  3. 开始寻找凸包;
  • 第一步,P0和P1与P2去构建向量P0P1和P0P2,P1,P2,P3入栈
  • 第二步,P1和P2出栈,和P3构建向量P1P2,P1P3,所以P1和P3入栈
  • 第三步,以此类推,P1,P3出栈和P4构建向量,当向量的叉乘积大于0时,三者都进栈,否则中间点出栈,即P3出栈,两边点进栈(P1和P4进栈)

算法源码

1.寻找P0点

Point findPointMin(Point pointIn[], int size)
{
	Point pointOut = pointIn[0];
	for (int i = 1; i < size; i++)
	{
		if (pointOut.y > pointIn[i].y)
		{
			pointOut = pointIn[i];
		}
		else if (abs(pointOut.y - pointIn[i].y) < 0.000001)
		{
			if (pointOut.x > pointIn[i].x)
			{
				pointOut = pointIn[i];
			}
		}
	}
	return pointOut;
}

2.排序

bool sortPoint(Point a, Point b)
{
	bool stat = true;
	if (P0.x == a.x && P0.y == a.y)
		return true;
	if (P0.x == b.x && P0.y == b.y)
		return false;

	float angle_a = a.x == P0.x ? MAXFLOAT : (a.y - P0.y) / (a.x - P0.x);
	float angle_b = b.x == P0.x ? MAXFLOAT : (b.y - P0.y) / (b.x - P0.x);

	float length_a = (a.y - P0.y) * (a.y - P0.y) + (a.x - P0.x) * (a.x - P0.x);
	float length_b = (b.y - P0.y) * (b.y - P0.y) + (b.x - P0.x) * (b.x - P0.x);

	if (abs(angle_a - angle_b) <= 0.000001)
	{
		stat = length_a > length_b ? false : true;
	}

	if (angle_a < 0 && angle_b >= 0)
	{
		stat = false;
	}
	else if (angle_a >= 0 && angle_b < 0)
	{
		stat = true;
	}
	else
	{
		if (angle_a < angle_b)
		{
			stat = true;
		}
		else
		{
			stat = false;
		}
	}
	return stat;
}

3.寻找凸包

vector<Point> findConvexHull(Point pointIn[], int size)
{
	stack<Point> resultPoint;
	vector<Point> convexHull;
	queue<Point> tempPoint;
	float flag = 0;

	resultPoint.push(pointIn[0]);
	resultPoint.push(pointIn[1]);
	for (int i = 2; i < size; i++)
	{
		// if(((pointIn[i-1].y - P0.y) * (pointIn[i].x - P0.x)) == (pointIn[i-1].x-P0.x) * (pointIn[i].y - P0.y))
		// {
		// 	continue;
		// }
		Point p3 = pointIn[i];
		Point p2 = resultPoint.top();
		resultPoint.pop();
		Point p1 = resultPoint.top();

		flag = (p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y);

		if (flag > 0)
		{
			resultPoint.push(p2);
			resultPoint.push(p3);
		}
		else if (flag == 0)
		{
			resultPoint.push(p3);
		}
		else
		{
			while (1)
			{
				p2 = resultPoint.top();
				resultPoint.pop();
				p1 = resultPoint.top();
				flag = (p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y);
				if (flag <= 0)
				{
					resultPoint.push(p3);
					break;
				}
				else
				{
					resultPoint.push(p2);
					resultPoint.push(p3);
					break;
				}
			}
		}
	}
	cout << "result point" << endl;
	while (!resultPoint.empty())
	{
		Point temp = resultPoint.top();
		resultPoint.pop();

		cout << "(" << temp.x << "," << temp.y << ")" << endl;

		convexHull.push_back(temp);
	}
	return convexHull;
}

主函数

int main()
{
	vector<Point> convexHull;
	/* 测试数据*/
	// Point pointSet[10]={{1,2},{1,3},{0,3},{-1,3},{3,3},{4,3},{5,3},{-2,3},{6,3},{2,3}};
	// Point pointSet[10] = {{1, 0}, {2, 1}, {1, 3}, {2, 2}, {1, 2}, {3, 1}, {3, 3}, {3, 2}, {4, 1}};
	Point pointSet[10] = {{1, 0}, {1, 1}, {1, 3}, {2, 3}, {2, 2},{2,4}, {3, 3}, {3, 4}, {4, 3},{0,4}};
	/* 寻找P0*/
	P0 = findPointMin(pointSet, sizeof(pointSet) / sizeof(pointSet[0]));
	cout << "P0:" << P0.x << "  " << P0.y << endl;
	/* 按极角排序*/
	sort(pointSet, pointSet + 10, sortPoint);
	/* 寻找凸包*/
	convexHull = findConvexHull(pointSet, 10);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值