簡體   English   中英

順時針排序算法的優化

[英]Optimization of a clockwise sort algorithm

所以這是一個優化問題,我找不到答案。

我已經寫了一些代碼來計算給定隨機點集的凸包。 為了進行比較,我制作了自己的慢速O(n³)算法,使用了一些舊的OpenGL可視化它。 由於慢凸殼算法的性質,這些點根本沒有排序。 因此,排序僅在計算CH之后進行。

我的問題是,直到1000點,我在不到一秒鍾的時間內就獲得了視覺效果。 但是,要獲得10000點,則需要15到20分鍾的時間(我沒有等待更多)。 但是,如果我跳過排序代碼,並讓opengl顯示未排序的凸包頂點,則只需不到一分鍾的時間。 因此,正是ClockWise排序一直困擾着我們。 檢查代碼(某些名稱沒有意義,因為它們是在其他地方定義的):

// This code actually compares every pair iteratively with respect to the center point
// Consider a given vector "convex", which contains all the convex hull points unsorted

.
..
...
....

int avgx,avgy,sumx=0,sumy=0;

for (int i=0;i<convex.size();i++){
    sumx+=convex.at(i).at(0);
    sumy+=convex.at(i).at(1);
}

avgx=sumx/(convex.size()/2.0); //something like an internal point
avgy=sumy/(convex.size()/2.0);

sort(convex.begin(),convex.end()); //x-sort 
int det,tempx,tempy;
for (int i=0;i<convex.size()-1;i++){
    x1=convex.at(i).at(0);
    y1=convex.at(i).at(1);
    x2=convex.at(i+1).at(0);
    y2=convex.at(i+1).at(1);
    det=(x1-avgx)*(y2-avgy)-(x2-avgx)*(y1-avgy); 
    if (det<0){ //on which side of O-X1 lies X2?
        tempx=convex.at(i).at(0); //swapping points 
        tempy=convex.at(i).at(1);
        convex.at(i).at(0)=convex.at(i+1).at(0);
        convex.at(i).at(1)=convex.at(i+1).at(1);
        convex.at(i+1).at(0)=tempx;
        convex.at(i+1).at(1)=tempy;
        i=-1; //check again the new vector from the beginning
    }
    }
return convex;

顯示部分:

glColor3f(0.8, 0.2, 0.2);
glPointSize(3);
glBegin(GL_LINE_LOOP);
    for (int i=0;i<count;i++){
        glVertex2f(convexHull.at(i).at(0),convexHull.at(i).at(1));
    }
glEnd();

據我所知,這種方法(通過比較交叉產品)是最有效的。 但是,在此之前,我寫了一些骯臟的代碼,實際上速度更快,因為它在8分鍾內給了我視覺效果。 我不想保留它,因為它太臟太長了,它比較干凈但是很慢(如果它真的可以工作的話……)。 那么,我是否應該等待10000個凸點的CW這么多,還是我缺少什么?

如有任何想法,我將不勝感激,如果需要添加其他內容,請告知我。

一般來說,這個問題有點奇怪。 大多數2D凸包算法(我所知道的所有算法)都按順時針或逆時針順序給出點(頂點)列表,或者可以對其進行簡單修改。

無論如何,由於有幾種良好的2D凸包確定方法可以在O(N ^ 2)或更快的速度下運行,因此您可以使用其中一種將數據按順時針順序“排序”。 我的意思是,您可以對數據運行CH算法,並按所需順序獲得結果。

這是我想得到的示例代碼,它可以滿足您的要求:

#define TURN_DIR(p1,p2,p3)  (p1.x * p2.y - p1.y * p2.x + \
                             p2.x * p3.y - p2.y * p3.x + \
                             p3.x * p1.y - p3.y * p1.x)
#define LAST(cntnr)         (cntnr).back()
#define BEFORE_LAST(cntnr)  (cntnr)[(cntnr).size() - 2]

void ConvexHull (std::vector<Point> & pts)
{
    std::sort (pts.begin(), pts.end());

    std::vector<Point> lower, upper;
    for (unsigned i = 0; i < pts.size(); ++i)
    {
        while (lower.size() > 1 && TURN_DIR(BEFORE_LAST(lower), LAST(lower), pts[i]) <= 0)
            lower.pop_back ();
        while (upper.size() > 1 && TURN_DIR(BEFORE_LAST(upper), LAST(upper), pts[i]) >= 0)
            upper.pop_back ();

        lower.push_back (pts[i]);
        upper.push_back (pts[i]);
    }

    upper.insert (upper.end(), lower.rbegin() + 1, lower.rend() - 1);
    pts.swap (upper);
}

有幾點要考慮:

  1. 上面的代碼接收其輸入,並以相同的參數pts返回其輸出。
  2. Point結構是一個簡單的結構(或類),具有兩個公共成員xy ,以及一個小於運算符( operator < ),該operator <非常簡單地根據xy
  3. 我相信以上代碼的運行時間為O(N * log(N)) ,但肯定不比O(N ^ 2)差
  4. 返回的點將按順時針順序排列。 如果要逆時針旋轉,只需更改最后兩行。
  5. 這段代碼無法處理所有點都具有相同X坐標的情況(我認為!)
  6. 除此之外,這是一個功能強大且快速簡單的2D凸包實現。
  7. 如果輸入中有連續的點位於同一行上,則此實現將其刪除。 如果不希望這樣,可以將while循環中的<= 0>= 0測試分別替換為< 0> 0

讓我強調一下:盡管上面的代碼是CH實現,但是您可以使用它僅按順時針纏繞順序對點進行排序(如果它們已經形成凸包)。

您已經實現了Bubble Sort ,它是O(n 2 )。 您可以通過將STL sort與適當的比較函子一起使用來獲得O(n log(n))。

這是第一步。 它使用了非傳遞比較器,但似乎可以在我的測試用例中使用,並且我認為通常是正確的:

struct clockwise : public binary_function<vector<int>, vector<int>, bool>
{
  bool operator()(vector<int> A, vector<int> B)
  {
    int det=(A[0]-avgx)*(B[1]-avgy)-(B[0]-avgx)*(A[1]-avgy);
    return(det<0);
  }

  static int avgx, avgy;
};

int clockwise::avgx = 0;
int clockwise::avgy = 0;

...

int clockwise::avgx=sumx/(convex.size()/2.0);
int clockwise::avgy=sumy/(convex.size()/2.0);
sort(convex.begin(),convex.end(), clockwise()); //clockwise-sort

編輯:

非傳遞式比較器不是一個好主意。 這是更可靠的:

#include <math.h>

...

struct clockwise : public binary_function<vector<int>, vector<int>, bool>
{
  bool operator()(vector<int> A, vector<int> B)
  {
    return(atan2(A[0]-avgx, A[1]-avgy) < atan2(B[0]-avgx, B[1]-avgy));
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM