幾何:極角排序詳解


關於極角排序:

  在平面內取一個定點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了。

  所以兩種方法根據情況選擇一種合適的使用。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM