Graham Scan凸包算法实现

今天实现以下Graham Scan算法算法,看了网上的资料,个人理解
1、找左下角点
2、对所有点相对该点的极角进行排序
3、将1、2入栈,以后的点逐个入栈,下一个新点如果满足逆时针旋转(右手准则),则该点入栈,如果是顺时针则该点放弃,再重复步骤 3,直到扫描到最后一个点结束
这里可以参考:https://blog.csdn.net/houszchina/article/details/79271765
https://blog.csdn.net/allenjiao/article/details/83828021

一下代码是参考别人的,主要把输入和输出参量用容器代替

#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
struct Point
{
 float x, y;
};
//小于0,说明向量p0p1的极角大于p0p2的极角,大于零,逆时针,小于零,顺时针
float multiply(Point p1, Point p2, Point p0)
{
 return((p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y));
}
float dis(Point p1, Point p2)
{
 return(sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y)));
}
vector<Point> My_Graham_Scan(vector<Point> PointSet, vector<Point> hull)   // Graham扫描法
{
 int i, j, k = 0, top = 2;
 Point tmp;
 int n = PointSet.size();
 //找到最下且偏左的那个点
 for (i = 1; i < n; i++)
 {
  if ((PointSet[i].y < PointSet[k].y) || ((PointSet[i].y == PointSet[k].y) && (PointSet[i].x < PointSet[k].x)))
  {
   k = i;
  }
 }
 //将这个点指定为PointSet[0]
 tmp = PointSet[0];
 PointSet[0] = PointSet[k];
 PointSet[k] = tmp;
 //按极角从小到大,距离偏短排前进行遍历排序
 for (i = 1; i<n - 1; i++)
 {
  k = i;
  for (j = i + 1; j<n; j++)
  {
   if ((multiply(PointSet[j], PointSet[k], PointSet[0])>0)         // k角大于i角 即基准角大于判断角,进行交换
    || ((multiply(PointSet[j], PointSet[k], PointSet[0]) == 0)
    && (dis(PointSet[0], PointSet[j]) < dis(PointSet[0], PointSet[k]))))    // 最近点  即基准角大于判断角,进行交换
   {
    k = j; //k保存极角最小的那个点,或者相同距离原点最近
   }
  }
  tmp = PointSet[i];
  PointSet[i] = PointSet[k];
  PointSet[k] = tmp;
 }
 //初始第一对向量,其中0,1位点边界
 hull.push_back(PointSet[0]);
 hull.push_back(PointSet[1]);
 hull.push_back(PointSet[2]);
 //判断与其余所有点的关系
 for (i = 3; i<n; i++)
 {
  // 不满足向左转的关系,栈顶元素出栈
  while (multiply(PointSet[i], hull[top], hull[top - 1]) >= 0)
  {
   top--;
   hull.pop_back();
  }
  //当前点与栈内所有点满足向左关系,因此入栈.
  hull.push_back(PointSet[i]);
  ++top;
 }
 return hull;
}
void main()
{
 vector<Point> dot, hull;
 Point p;
 p.x = 10;
 p.y = 20;
 dot.push_back(p);
 p.x = 3;
 p.y = 5;
 dot.push_back(p);
 p.x = 6;
 p.y = 2;
 dot.push_back(p);
 p.x = 8;
 p.y = 10;
 dot.push_back(p);
 p.x = 15;
 p.y = 10;
 dot.push_back(p);
 p.x = 7;
 p.y = 9;
 dot.push_back(p);
 p.x = 8;
 p.y = 1;
 dot.push_back(p);
 p.x = 4;
 p.y = 3;
 dot.push_back(p);
 hull =  My_Graham_Scan(dot, hull);
 for(int i = 0; i < hull.size(); i++)
 {
  cout << "x:" << hull[i].x << " y:" << hull[i].y << endl;
 }
 system("pause");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值