求平面散點集的凸包


本文參考自<<算法導論>>章節33.3 尋找凸包

完整VS2010工程見(包含測試數據與效果演示):

Graham算法主要利用向量的叉積判斷點和線段的位置關系,詳見 向量叉積,然后從左下角點按逆時針方向尋找最邊緣的線段,利用的原理就是從凸包上任意一點逆時針出發,每到一個節點,一定會向左拐.算法復雜度為O(nlg(n))

算法主要實現如下:

 1 // 輸入:點數組arrInPt,個數nInPtCount,包含所有點
 2 // 輸出:點數組arrOutPt,個數nOutPtCount,逆時針順序依次存放凸包上的點
 3 static void Graham(Point arrInPt[],const int nInPtCount,Point arrOutPt[],int & nOutPtCount)
 4 {
 5     // step 1:找到最靠近坐下角的點,放到p[0]位置
 6     // 保證p[0]的y值最小,若兩點y值相同,取x值較小者
 7     int nIndex = 0;
 8     for(int i = 1;i < nInPtCount;++i)
 9     {
10         if(arrInPt[i].y < arrInPt[nIndex].y ||
11             (arrInPt[i].y == arrInPt[nIndex].y && arrInPt[i].x < arrInPt[nIndex].x))
12         {
13             nIndex = i;
14         }
15     }
16     Point tmp = arrInPt[0];
17     arrInPt[0] = arrInPt[nIndex];
18     arrInPt[nIndex] = tmp;
19 
20     // step 2:剩下的點p[1]--p[nInPtCount-1],按照與p[0]極角升序排序
21     SortByPolarAngle(arrInPt,nInPtCount);
22 
23     // step 3:棧操作
24     nOutPtCount = 0;
25     // 前三個點入棧
26     arrOutPt[nOutPtCount++] = arrInPt[0];
27     arrOutPt[nOutPtCount++] = arrInPt[1];
28     arrOutPt[nOutPtCount++] = arrInPt[2];
29     for(int i = 3;i < nInPtCount;i++)
30     {
31         // 棧中最上面兩個點如果不與arrInPt[i]形成左轉,就進行出棧操作
32         while(nOutPtCount > 1 && IfTurnLeft(arrOutPt[nOutPtCount-2],arrOutPt[nOutPtCount-1],arrInPt[i]) == false )
33         {
34             nOutPtCount--;
35         }
36         // arrInPt[i]入棧
37         arrOutPt[nOutPtCount++] = arrInPt[i];
38     }
39 }

Jarvis算法與Graham算法類似也是從左下角的點開始,依次搜尋與邊界點極角最小的點.算法復雜度為O(hn),h為邊界點的個數

 1 // 輸入:點數組arrInPt,個數nInPtCount,包含所有點
 2 // 輸出:點數組arrOutPt,個數nOutPtCount,逆時針順序依次存放凸包上的點
 3 static void Jarvis(Point arrInPt[],const int nInPtCount,Point arrOutPt[],int & nOutPtCount)
 4 {
 5     // step 1:找到最靠近坐下角的點,放到p[0]位置
 6     // 保證p[0]的y值最小,若兩點y值相同,取x值較小者
 7     nOutPtCount = 0;
 8     int nIndex = 0;
 9     for(int i = 1;i < nInPtCount;++i)
10     {
11         if(arrInPt[i].y < arrInPt[nIndex].y ||
12             (arrInPt[i].y == arrInPt[nIndex].y && arrInPt[i].x < arrInPt[nIndex].x))
13         {
14             nIndex = i;
15         }
16     }
17     Point tmp = arrInPt[0];
18     arrInPt[0] = arrInPt[nIndex];
19     arrInPt[nIndex] = tmp;
20     // step : 尋找與p[nIndex]極角最小的那個點
21     nIndex = 0;
22     do 
23     {
24         arrOutPt[nOutPtCount++] = arrInPt[nIndex];
25         nIndex = FindMinPolarAngle(arrInPt,nInPtCount,nIndex);
26     } while (arrInPt[0] != arrInPt[nIndex]);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
27 }

經測試,兩種算法的效率差不多,10W個點以內,1s之內可以搞定,100w個點,Jarvis大約需要5秒多,Graham大約需要6s多,也就是h < log(n)時,Jarvis效率略優.測試機器為i5 3.10GHz

Graham效率:

Jarvis效率:


免責聲明!

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



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