凸包问题(2)------graham扫描法

#include
#include
#include
#include
using namespace std;
 
vector> findNodes(vector>& arr);
bool sortByAngle(vector& a, vector& b);
bool isOrigin(vector& a, vector& b);
bool isOnLeft(vector curNode, vector topMinuOne, vector top);
double distance(vector &a, vector &b);
void test1();
void test2();
 
vector originPoint;
double originX;
double originY;
 
int main() {
	test1();   //当坐标数组为空时候,测试1
	test2();  //当扫描时候有多个坐标在一条直线上时,测试2
}
 
void test1() {
	cout << "test1()输入为空数组:" << endl;
	vector> temp;
	if (findNodes(temp).size() == 0) {
		cout << "test1()输出为空数组,正确"     <> temp = { { 1,1 },{ 2,2 },{ 2,0 },{ 2,4 },{ 3,3 },{ 4,2 } };
	//vector>     temp = { {1,1},{2,1},{3,1},{2,2},{3,3},{2,3},{1,3} };
	//vector>     temp = { {1,1},{1,1},{1,1},{1,1},{1,1},{1,1} };
	cout << "test2()输入是:     " << "{
    {1,1},{2,2},{2,0},{2,4},{3,3},{4,2}}" << endl;
	vector> ans = findNodes(temp);
	cout << "test2()输出结果是:{";
	for (int i = 0; i < ans.size(); i++) {
		cout << '{' << ans[i][0] << "," << ans[i][1] << "},";
	}
	cout << '}' << endl;
	cout << "test2()正确结果是:" << "{
    {2,0},{4,2},{2,4},{1,1}}";
}
 
//Description: 找出凸包上的坐标点,会先找到一个极点然后进行逆时针扫描
vector> findNodes(vector>& arr) {
 
	sort(arr.begin(), arr.end(), isOrigin); //排序目的有两个,一是用于查找第一个节点(左下角)
	int nodeNum = arr.size();				//二是为了给坐标点去重
	for (int i = 0; i < nodeNum - 1; i++) {
		if ((arr[i][0] == arr[i + 1][0]) && (arr[i][1] == arr[i + 1][1])) {
			arr.erase(arr.begin() + i);
			nodeNum = arr.size();
			i--;
		}
	}
 
	nodeNum = arr.size(); //计算去重后剩下的坐标点的个数
	if (nodeNum <= 2) { //数组为空或者坐标点为1,2这些简单情况就直接返回
		return arr;
	}
 
	originPoint = arr[0];
	originX = originPoint[0];
	originY = originPoint[1];
 
	sort(arr.begin() + 1, arr.end(), sortByAngle); //根据角度大小进行排序,角度一样大的按照距离小的在前
 
	vector> ans;
	ans.push_back(originPoint);	//把极点先存入
 
	int i = 1;
	ans.push_back(arr[i++]);
	int top = 1;
	while (i < nodeNum) {  //检查每一个节点是否属于凸包
		if (isOnLeft(arr[i], ans[top - 1], ans[top])) {
			ans.push_back(arr[i++]);
			top++;
		}
		else {
			if (ans.size() == 2) { //如果刚开始的几个点都在一条直线上,那么ans里面第二个点会被剔除,导致数组越界
				ans.pop_back();
				ans.push_back(arr[i++]);
			} else {
				ans.pop_back();
				top--;
			}
		}
	}
	return ans;
}
 
//Description: 判断三点构成的连线的相对位置
bool isOnLeft(vector cur, vector topMinuOne, vector top) {
	int cross = (cur[0] - topMinuOne[0])*(top[1] - topMinuOne[1]) - (top[0] - topMinuOne[0])*(cur[1] - topMinuOne[1]); //x1y2-x2y1 计算叉积
	if (cross > 0) {
		return false;
	}
	else if (cross < 0) {
		return true;
	}
	else { //叉积等于0的时候,说明点共线,要进行判断一下
		if (distance(cur, topMinuOne) > distance(top, topMinuOne)) {
			return false;
		}
		return true;
	}
}
 
bool isOrigin(vector& a, vector& b) {
	if (a[1] == b[1]) { //纵坐标相等的时候,横坐标小的在前
		return a[0] < b[0];
	}
	return a[1] < b[1];
}
 
double distance(vector &a, vector &b) {
	return (pow((a[0] - b[0]), 2) + pow((a[1] - b[1]), 2));
}
 
bool sortByAngle(vector& a, vector& b) {
	if (abs(atan2(a[1] - originY, a[0] - originX) - atan2(b[1] - originY, b[0] - originX)) < 1e-8) { //浮点数比较是否相等,只能取一个范围
		return distance(a, originPoint) < distance(b, originPoint);
	}
	return atan2(a[1] - originY, a[0] - originX) < atan2(b[1] - originY, b[0] - originX);
}

 

你可能感兴趣的:(凸包问题(2)------graham扫描法)