凸包问题之GrahamScan法

本文详细介绍了Graham扫描算法的基本原理及其实现过程。该算法通过计算极角大小并进行排序来找出凸包上的顶点,适用于二维空间中点集的凸包问题。文章提供了完整的C语言实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值