点集Q的凸包是一个最小的凸多边形P,满足Q中的每个点或者在P的边界上,或者在P的内部。
主要介绍Graham扫描算法,时间复杂度为O(nlgn)。
算法:通过设置一个关于候选点的堆栈S来解决凸包问题。输入集合Q中的每个点都压入栈一次,非CH(Q)中顶点的点最终被弹出堆栈。当算法终止时,堆栈
S中仅包含CH(Q)中的顶点,其顺序为各点在边界上出现的逆时针方向排序的顺序。
Graham_Scan(Q):
int Graham()
{
int i, top, tmp = 0;
for(i = 1; i < n; i++)
if((map[i].y<map[tmp].y) || (map[i].y == map[tmp].y && map[i].x < map[tmp].x))
tmp = i;
Point p = map[tmp];
map[tmp] = map[0];
map[0] = p;
sort(map + 1, map + n, cmp);
S[0] = map[0];
S[1] = map[1];
S[2] = map[2];
top = 2;
for(i = 3; i < n; i++)
{
while(direction(S[top - 1],map[i],S[top]) > 0)
top--;
S[++top] = map[i];
}
return top;
}
int direction(Point p0, Point p1, Point p2)
{
return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}
int cmp(Point p1, Point p2)
{
if(direction(map[0],p1,p2) > 0)
return 1;
else if(direction(map[0],p1,p2) == 0 && (dist(map[0],p1)-dist(map[0],p2) < 0))
return 1;
return 0;
}