c语言凸包算法,基于C语言的凸包算法实现
基于C語言的凸包算法實現
非計算機專業,代碼有些的不好的地方,大佬輕噴^ _ ^
根據要求,需要使用C語言實現凸包算法——Graham掃描法,本文將從算法理解、實現思路、遇到的問題及其解決方案三個方面來闡述實現過程。
算法理解
凸包算法Graham掃描法,在不考慮排序算法的時間復雜度情況下,算法核心程序的時間復雜度為 O ( n l o g n ) O(n log n)O(nlogn),其主要算法思想如下:
首先是預處理過程,獲得一組隨機點集,選取位于二維空間中左下角的點,即在縱坐標(y)最小情況下橫坐標(x)為最小的點P 0 P_0P0? 。以該點位極坐標原點計算其余各點的極角θ \thetaθ,并根據極角大小進行升序排序,若極角相同則按極徑大小按升序排列。由此得到一組按照極角排序的點集 { P 0 , P 1 , . . . , P n } \left\{P_0,P_1,...,P_n\right\}{P0?,P1?,...,Pn?}(如下圖所示)。
完成預處理之后即Graham算法的核心步驟,主要通過棧的方式來實現凸包點的計算。首先將P 0 , P 1 P_0,P_1P0?,P1?兩點壓棧,他們必然屬于凸包上的點。然后進入迭代過程,以棧頂元素A [ t o p ] A[top]A[top]和次棧頂元素 A [ t o p ? 1 ] A[top-1]A[top?1]構成的向量a ? \vec{a}a為基準計算其與當前P k P_kPk?點與棧頂元素A [ t o p ] A[top]A[top]構成的向量b ? \vec{b}b的叉積 ,若結果為正(零)則 b ? \vec{b}b 位于 a ? \vec{a}a 的逆時針方向(共線),P k P_kPk?進棧 ,若結果為負則 b ? \vec{b}b 位于 a ? \vec{a}a 的順時針方向, A [ t o p ] A[top]A[top]出棧, P k P_kPk?進棧,直至掃描至最后一個點,將 P 0 P_0P0? 再次進棧是凸包閉合。
由于要求順時針輸出凸包頂點,則將棧中元素從棧頂向棧底依次輸出即可。
實現思路及過程
根據Graham掃描法的算法理解,將程序實現分為了隨機點坐標初始化、極角計算及排序、Graham核心算法和結果輸出四個模塊共計8個函數進行編碼實現。
結構體定義
// 點坐標
typedef struct POINT {
int x;
int y;
}Point;
坐標初始化
首先構造存儲點坐標的結構體Point,該結構體中僅包含橫坐標x和縱坐標y。根據要求需要隨機生成100個點,使用宏定義點集大小(SIZE)為100。使用庫下的rand()函數以當前系統時間為種子生成 0 ≤ x < 50 , 0 ≤ y < 50 0\le x<50,0\le y<500≤x<50,0≤y<50 的點,并依次存入大小為SIZE的Point的類型的一維數組中。
void InitPoint(Point* p) {
int i;
srand(time(0));
for (i = 0; i < SIZE; i++) {
(p + i)->x = (int)(rand() % 50);
(p + i)->y = (int)(rand() % 50);
}
}
極角計算及排序
首先選取點集中位于左下角的點,采用的方法為先找出縱坐標 最小的坐標點(集),然后在其中找出橫坐標 最小的坐標點,記錄該點位于原始點集的位置,將其與第一個點進行交換。接著使用庫下的atan()函數計算各點的極角,并將其記錄在double類型大小為SIZE的一維數組angle中,令極坐標原點的極角: a n g l e [ 0 ] = 0 angle[0] = 0angle[0]=0。使用冒泡排序算法對極角進行排序,同時改變點集中各點的順序。在排序是要考慮當極角相同時按極徑從小到大排序。
Graham核心算法
根據算法分析結果,定義一個Point類型的一維數組作為棧空間,定義棧頂定位變量top,用于標記棧頂元素在棧中的位置,定義臨時變量temp_point用記錄當前掃描到的坐標點,定義叉積計算函數,返回值為布爾類型。當叉積為非負時返回true,否則返回false。判斷temp_point和棧頂元素,次頂元素三個點組成的兩個向量的方向,若叉積返回值為正,則將temp_point進棧,否則將當前棧頂元素出棧,繼續判斷現在的棧頂元素和次頂元素與temp_point三個點的向量叉積……
得到包含所有凸包頂點的棧數組,最后將 點進棧形成封閉凸包,在形成封閉凸包前需要對 以及當前棧頂和次頂元素進行判斷是否符合凸包結構,若符合則將 進棧,反之將當前棧頂元素出棧,重復判斷步驟直至符合為止。
int myGraham(Point* p, Point* p_stack) {
int top = -1; //棧頂指針
int p_index = 0; //點索引
Point temp_point;
top++; p_stack[top] = p[0]; p_index++; //push
top++; p_stack[top] = p[1]; p_index++; //push
while (p_index < SIZE) {
temp_point = p[p_index];
if (X(p_stack[top - 1], p_stack[top], temp_point))
{
top++; p_stack[top] = temp_point;//push
}
else {
top--;//pop
continue;
}
p_index++;
}
while (TRUE) {
if (!X(p_stack[top - 1], p_stack[top], p[0])) {
top--;
}
else {
break;
}
}
top++; p_stack[top] = p[0];
return top;
}
結果輸出
為了使結果更直觀,定義了一個輸出函數,能夠輸出凸包頂點坐標,并在二維坐標中,顯示點。
運行結果
來源:oschina
鏈接:https://my.oschina.net/u/4355012/blog/4274913
總結
以上是生活随笔為你收集整理的c语言凸包算法,基于C语言的凸包算法实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android Studio ---
- 下一篇: iOS开发入门笔记