GrahamScan法:当沿着Convex hull逆时针漫游时,总是向左转;在极坐标系下按照极角大小排列,然后逆时针方向漫游点集,去除非Conves hull顶点(非左转点)。
实现代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#define MAX_SIZE 10001
struct Point{
int x,y;
};
//在比较极角大小时作为标准的点
struct Point p0;
//计算极角大小
double cross(struct Point p1,struct Point p2,struct Point p0)
{
return ((p1.x - p0.x) * (p2.y-p0.y) - (p1.y-p0.y) * (p2.x-p0.x));
}
//计算两点间距离
double Distance(struct Point a,struct Point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
//按极角大小排序
int cmpGraham(const void *a,const void *b)
{
double i;
struct Point* a1 = (struct Point *)a;
struct Point* b1 = (struct Point *)b;
/*if((*(struct Point *)a).y == p0.y)
return 0;
if((*(struct Point *)b).y == p0.y)
return 1;*/
i = cross(*a1,*b1,p0);
if(i<0)
return 1;
else if(i==0 && Distance(*a1, p0) >= Distance(*b1, p0))
return 1;
else
return -1;
}
int GrahamScan()
{
int n,k,i,top,j;
int stack[MAX_SIZE];
struct Point p[MAX_SIZE];
struct Point left[MAX_SIZE];
struct Point right[MAX_SIZE];
// CPU频率
LARGE_INTEGER li;
// 记录过程时间
LONGLONG start,end,fred;
// 获取CPU频率
QueryPerformanceFrequency(&li);
fred = li.QuadPart;
freopen("input.txt", "r", stdin);
freopen("outputgs.txt","w",stdout);
while(scanf("%d", &n) != EOF)
{
top = 0;
scanf("%d %d",&p[0].x,&p[0].y);
p0 = p[0];
k=0;
for(i=1;i<n;i++)
{
scanf("%d %d",&p[i].x,&p[i].y);
//得到y轴值最小的点,若y值相同则选择x值较小者
if(p0.y>p[i].y || (p0.y==p[i].y && p0.x>p[i].x))
{
p0 = p[i];
k=i;
}
}
//start = GetTickCount();
QueryPerformanceCounter(&li);
start = li.QuadPart;
//将第一个点换为y轴上值最小的点
p[k] = p[0];
p[0] = p0;
//关于极角排序,确定p0后,就变成在另一个坐标系下了
k=0;j=0;
for(i=1;i<n;i++)
{
if(p[i].x<p0.x)
left[j++] = p[i];
else
right[k++] = p[i];
}
for(i=1;i<k+1;i++)
p[i] = right[i-1];
for(;i<n;i++)
p[i] = left[i-k-1];
qsort(p+1,k,sizeof(p[0]),cmpGraham);
qsort(p+k+1,j,sizeof(p[0]),cmpGraham);
//qsort(p+1,n-1,sizeof(p[0]),cmpGraham1);
//栈操作
stack[0] = 0;
stack[1] = 1;
stack[2] = 2;
top = 2;
for(i=3;i<n;i++)
{
while(top>1 && g(p[i],p[stack[top-1]],p[0])*g(p[i],p[stack[top-1]],p[stack[top]])>=0)
top--;
stack[++top] = i;
}
//end = GetTickCount();
// 获取结束时间
QueryPerformanceCounter(&li);
end = li.QuadPart;
printf("结果集:\n");
j=0;
for(i=0;i<=top;i++)
{
printf("%d,%d\t",p[stack[i]].x,p[stack[i]].y);
j++;
if(j%5 == 0) printf("\n");
}
printf("\n");
//printf("经历时间为%.2f\n\n",end-start);
printf("经历时间为%dms\n\n",(int)1000 * (end-start) / fred);
}
return 0;
}