几何:极角排序详解

关于极角排序:

  在平面内取一个定点O,叫极点,引一条射线Ox,叫做极轴,再选定一个长度单位和角度的正方向(通常取逆时针方向)。

  对于平面内任何一点M,用ρ表示线段OM的长度(有时也用r表示),θ表示从Ox到OM的角度,ρ叫做点M的极径,θ叫做点M的极角,有序数对 (ρ,θ)就叫点M的极坐标。

  那么给定平面上的一些点,把它们按照一个选定的中心点排成顺(逆)时针。

极角排序常用的四种方法:

  在说四种方法之前,给出一会用到的函数和存储点的结构体

struct point//存储点
{
    double x,y;
};

double cross(double x1,double y1,double x2,double y2) //计算叉积
{
    return (x1*y2-x2*y1);
}

double compare(point a,point b,point c)//计算极角
{
    return cross((b.x-a.x),(b.y-a.y),(c.x-a.x),(c.y-a.y));
}

方法1:利用atan2()函数按极角从小到大排序。

    关于atan2()函数:在C语言的math.h或C++中的cmath中有两个求反正切的函数atan(double x)与atan2(double y,double x)  他们返回的值是弧度要转化为角度再自己处理下。

前者接受的是一个正切值(直线的斜率)得到夹角,但是由于正切的规律性本可以有两个角度的但它却只返回一个,因为atan的值域是从-90~90 也就是它只处理一四象限,所以一般不用它。

第二个atan2(double y,double x) 其中y代表已知点的Y坐标,同理x ,返回值是此点与远点连线与x轴正方向的夹角,这样它就可以处理四个象限的任意情况了,它的值域相应的也就是-180~180了

bool cmp1(point a,point b)
{
    if(atan2(a.y,a.x)!=atan2(b.y,b.x))
        return atan2(a.y,a.x)<atan2(b.y,b.x);
    else return a.x<b.x;
}

方法2:利用叉积按极角从小到大排序。

    关于叉积:叉积=0是指两向量平行(重合);叉积>0,则向量a在向量b的顺时针方向(粗略的理解为在a在b的下方);叉积<0,则向量a在向量b的逆时针方向(粗略的理解为在a在b的上方)

bool cmp2(point a,point b) 
{
    point c;//原点
    c.x = 0;
    c.y = 0;
    if(compare(c,a,b)==0)//计算叉积,函数在上面有介绍,如果叉积相等,按照X从小到大排序
        return a.x<b.x;
    else return compare(c,a,b)>0;
}

方法3:先按象限从小到大排序 再按极角从小到大排序

int Quadrant(point a)  //象限排序,注意包含四个坐标轴
{
    if(a.x>0&&a.y>=0)  return 1;
    if(a.x<=0&&a.y>0)  return 2;
    if(a.x<0&&a.y<=0)  return 3;
    if(a.x>=0&&a.y<0)  return 4;
}


bool cmp3(point a,point b)  //先按象限从小到大排序 再按极角从小到大排序
{
    if(Quadrant(a)==Quadrant(b))//返回值就是象限
        return cmp1(a,b);
    else Quadrant(a)<Quadrant(b);
}

 

关于三种方法的比较:

  第三种方法按象限从小到大排序 再按极角从小到大排序是在有特殊需求的时候才会用到,这里不做比较。

  关于第一种方法,利用atan2排序,他和利用叉积排序的主要区别在精度和时间上。

  具体对比:时间:相较于计算叉积,利用atan2时间快,这个时间会快一点(记得做过一个题用atan2排序过了,用叉积的T了)

         精度: atan2精度不如叉积高,做过一个题用anat2因为精度问题WA了。

  所以两种方法根据情况选择一种合适的使用。

 

转载于:https://www.cnblogs.com/aiguona/p/7248311.html

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值