C語言實現凸包Graham_scan算法

算法就不介紹了,其他地方應該也搜得到。

如何判斷三點A, B, C連線是逆時針?

(1) 通過判斷C在AB連線上方還是下方判斷,但需要根據斜率的正負,A, B位置關係分類討論,比較麻煩。
(2) 通過計算向量叉積的方法。
在一般的常識或者教科書中規定叉乘只有3維才擁有,其實2維也可以拓展出來一個叉乘形式。
拓展方式:假設有兩個2維向量a,b,我們直接把他們視爲3維向量,z軸補0,那麼這個時候的a,b向量的叉乘結果c,c.x=0,c.y=0,c.z=a.x* b.y-b.x *a.y。
有這樣的性質:設k是a,b向量的叉積,如果k>0時,那麼a正旋轉到b的角度爲<180°,如果k<0,那麼a正旋轉到b的角度爲>180°,如果k=0 那麼a,b向量平行。

代碼

#include<stdio.h>
#include<math.h>
#include<time.h>
#include<stdlib.h>
#define PI 3.14159
typedef struct Point {
	int x, y;
	double angle;
}Point;
int less(Point a, Point b) {		//定義點a小於點b法則(排序用)
	if (a.angle != b.angle) return a.angle < b.angle;
	else return a.x < b.x;
}
int ifAnticlockwise(Point a, Point b, Point c) {	//是否爲逆時針
	int crossProduct = (b.x - a.x)*(c.y - b.y) - (b.y - a.y)*(c.x - b.x);	//求向量積
	return crossProduct >= 0;	//向量積爲正表示逆時針
}
int main() {
	srand((unsigned)time(NULL));
	int n, minx, maxx, miny, maxy;
	scanf("%d%d%d%d%d", &n, &minx, &maxx, &miny, &maxy);
	Point point[105];
	for (int i = 0; i < n; i++) {	//生成隨機座標
		point[i].x = rand() % (maxx - minx + 1) + minx;
		point[i].y = rand() % (maxy - miny + 1) + miny;
	}
	double sx = 1000, sy = 1000;
	for (int i = 0; i < n; i++) {		//尋找起始點
		if (point[i].y < sy) sx = point[i].x, sy = point[i].y;
		else if (point[i].y == sy && point[i].x < sx) sx = point[i].x;
	}
	for (int i = 0; i < n; i++) {		//求夾角
		if (point[i].x == sx && point[i].y == sy) point[i].angle = 0;
		else if (point[i].x == sx) point[i].angle = 90;
		else {
			point[i].angle = atan((point[i].y - sy)*1.0 / (point[i].x - sx));
			if (point[i].angle < 0) point[i].angle = PI + point[i].angle;	
//轉換爲與x軸正方向夾角
		}
	}
	for (int i = 0; i < n - 1; i++) {
		for (int j = i + 1; j < n; j++) {	//冒泡排序
			if (less(point[j], point[i])) {
				Point temp = point[i];
				point[i] = point[j];
				point[j] = temp;
			}
		}
	}
	int cnt = 3;	//棧頂指針
	for (int i = 3; i < n; i++) {

		if (ifAnticlockwise(point[cnt - 2], point[cnt - 1], point[i])) {
			point[cnt++] = point[i];	//模擬入棧
		}
		else point[cnt - 1] = point[i];	//模擬出棧+入棧
	}
	for (int i = cnt - 1; i >= 0; i--) {	//逆序輸出
		printf("%4d %4d    ", point[i].x, point[i].y);
	}
	return 0;
}

程序測試

爲了驗證程序的正確性,先縮小了樣本,隨機生成橫縱座標都在-10~10範圍內的6個點,輸出第一行爲隨機生成的6個點的橫縱座標,接着輸出結果。將點在matlab中繪製,可以驗證程序正確。

在這裏插入圖片描述在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章