Graham演算法 凸包問題

2021-05-25 13:38:44 字數 1418 閱讀 1198

graham演算法的思路,大概如下:對平面上的點的集合,從中找到有最小的y座標值的點p,然後根據其它點和p的連線與正x軸所成的角度將平面上的點進行排序,排序後,掃瞄從p開始的有序列表,如果所有的這些點都在凸包上,那麼每三個相繼的點,會組成乙個左旋,從另一方面說,如果相繼的三個點,p1,p2,p3,組成了乙個右旋,則可以立即去除p2,因為它不可能在凸包上!如此掃瞄到p3等於p時,掃瞄就結束,剩下的點,就全都是凸包上的點了!

這裡面有幾個難點:

1、如何根據他們的夾角,來對雙鏈表進行排序

2、如何判斷左右旋

3、如何掃瞄

針對第乙個問題,在下面的程式中,採用的是簡單的選擇排序,即每次在無序區內找到最大的元素,將其放到有序區內,因為這是對雙鏈表進行排序,就有雙鏈表的排序特點,但我認為採用插入,即斷開結點之間的聯絡始終不是好的辦法,所以採用了這種簡單的交換的方法,雖然效率慢了點,但是重在說明問題!

針對第二個問題,判斷左右旋,其實可以用乙個行列式的值來判定

|x1   x2  x3|

|y2   y2  y3|

|1    1     1 |

若該行列式為正,則為左旋,反之,則為右旋。其實這個行列式是根據點是在直線的上方還是下方而推斷出來的,用直線方程也可以判斷左右旋。

針對第三個問題看下面的**中的scan()函式就很清楚了!

下面是用c++寫的具體**:

#include #include using namespace std;

struct point

;typedef struct point type;

/*建立乙個雙向鍊錶*/

void creatlinklist_du(type *l,int n)

}void calculatecos(type *l)//找到y座標最小的元素,讓它是第乙個點,並計算每個點的cos值

p=p->next;

} float x0=pmin->x;

float y0=pmin->y;

p=l;

while(p) }

/*簡單選擇排序*/

void ******slectsort(type *l)//按cos值進行降序排序

if(p!=pmax)//將此最大值放進有序區,這裡只需要交換兩個結點的內容就可以了

}}float area(float x1,float y1,float x2,float y2,float x,float y)//計算三個點的左旋還是右旋

void scan(type *l)//順序掃瞄雙鏈表,判斷相繼的三個點是否組成左旋或是右旋

}while(!(p3==p && temp>=0.0));

} /*輸出雙向鍊錶中的元素*/

void outputlinklist_du(type *l)}

int main()

Graham凸包演算法簡介

凸包真是乙個神奇的演算法。對於平面上的一些點,我們要求凸包上所有的點,可以使用graham演算法 時間複雜度o nlogn 先找到最左下的點,把其他的點按叉積排序。然後維護乙個堆疊,每次利用叉積和棧頂比較判斷當前列舉到的點是否是凸包上的點,是則彈出棧頂元素 具體演算法click here 常熟巨大的...

graham求凸包演算法

問題 點集q的凸包 convex hull 是指乙個最小凸多邊形,滿足q中的點或者在多邊形邊上或者在其內。這個演算法是由數學大師葛立恆graham發明的,他曾經是美國數學學會ams att 首席科學家.see 模板 see include include using namespace std cl...

凸包問題 Graham掃瞄法

凸包點集q的凸包 convex hull 是指乙個最小凸多邊形,滿足q中的點或者在多邊形邊上或者在其內。右圖中由紅色線段表示的多邊形就是點集q 的凸包。頂點個數n 1 排序 在點集q中找最左下方的點p0,就是x座標和y座標都最小的點,其餘的點計算它們的極座標幅角,以幅角的非降序順序來排序,如果有幅角...