Graham算法求平面散点集的凸包

本文参考自<<算法导论>>章节33.3 寻找凸包

完整VS2010工程见:http://download.csdn.net/detail/tangxin19930330/9406625

算法主要利用向量的叉积判断点和线段的位置关系,详见 向量叉积,然后从左下角点按逆时针方向寻找最边缘的线段,利用的原理就是从凸包上任意一点逆时针出发,每到一个节点,一定会向左拐.算法复杂度为O(nlg(n))

算法主要实现如下:

 1 // 输入:点数组arrInPt,个数nInPtCount,包含所有点
 2 // 输出:点数组arrOutPt,个数nOutPtCount,逆时针顺序依次存放凸包上的点
 3 static void Graham(Point arrInPt[],const int nInPtCount,Point arrOutPt[],int & nOutPtCount)
 4 {
 5     // step 1:找到最靠近坐下角的点,放到p[0]位置
 6     // 保证p[0]的y值最小,若两点y值相同,取x值较小者
 7     int nIndex = 0;
 8     for(int i = 1;i < nInPtCount;++i)
 9     {
10         if(arrInPt[i].y < arrInPt[nIndex].y ||
11             (arrInPt[i].y == arrInPt[nIndex].y && arrInPt[i].x < arrInPt[nIndex].x))
12         {
13             nIndex = i;
14         }
15     }
16     Point tmp = arrInPt[0];
17     arrInPt[0] = arrInPt[nIndex];
18     arrInPt[nIndex] = tmp;
19
20     // step 2:剩下的点p[1]--p[nInPtCount-1],按照与p[0]极角升序排序
21     SortByPolarAngle(arrInPt,nInPtCount);
22
23     // step 3:栈操作
24     nOutPtCount = 0;
25     // 前三个点入栈
26     arrOutPt[nOutPtCount++] = arrInPt[0];
27     arrOutPt[nOutPtCount++] = arrInPt[1];
28     arrOutPt[nOutPtCount++] = arrInPt[2];
29     for(int i = 3;i < nInPtCount;i++)
30     {
31         // 栈中最上面两个点如果不与arrInPt[i]形成左转,就进行出栈操作
32         while(nOutPtCount > 1 && IfTurnLeft(arrOutPt[nOutPtCount-2],arrOutPt[nOutPtCount-1],arrInPt[i]) == false )
33         {
34             nOutPtCount--;
35         }
36         // arrInPt[i]入栈
37         arrOutPt[nOutPtCount++] = arrInPt[i];
38     }
39 }

测试结果和算法效率如下,10W个点以内,1s之内可以搞定,100w个点,大约需要6s多,测试机器为i5 3.10GHz

时间: 2024-10-05 17:56:17

Graham算法求平面散点集的凸包的相关文章

计算几何 平面最近点对 nlogn分治算法 求平面中距离最近的两点

平面最近点对,即平面中距离最近的两点 分治算法: int SOLVE(int left,int right)//求解点集中区间[left,right]中的最近点对 { double ans; //answer 0)    调用前的预处理:对所有点排序,以x为第一关键词y为第二关键字 , 从小到大; 1)    将所有点按x坐标分成左右两部分; /*      分析当前集合[left,right]中的最近点对,有两种可能: 1. 当前集合中的最近点对,点对的两点同属于集合[left,mid]或同属

poj2187 求平面最远点对,garham_scan算法求凸包

poj2187 求平面最远点对,garham_scan算法求凸包 Beauty Contest Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 29666   Accepted: 9180 Description Bessie, Farmer John's prize cow, has just won first place in a bovine beauty contest, earning the title 'M

Graham算法—二维点集VC++实现

一.凸包定义 通俗的说就是:一组平面上的点,求一个包含所有点的最小凸多边形,这个最小凸多边形就是凸包. 二.Graham算法思想 概要:Graham算法的主要思想就是,最终形成的凸包,即包围所有点的凸多边形,假定多边形是按逆时针方向生成的,那么多边形内部包围的所有点与多边形每个有向边的关系都是:点在有向边的左边.依照此思想,只要找到一个出发点,然后依此出发点按逆时针方向构建多边形,并保证每加入一条有向边时,都要满足其余点都在该边的左边. ***点与线的关系定义:平面上的三点P1(x1,y1),P

初学算法 - 求凸包的Garham‘s Scan算法的C++实现

所谓凸包,就是一个计算几何(图形学)中的概念.用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边型,它能包含点集中所有的点.维基百科对集合X的凸包(Convex Hull)有四个定义,分别为: The (unique) minimal convex set containing X            ---  包含集合X的最小凸集合 The intersection of all convex sets containing X          --- 所有包

平面上圆的凸包算法

平面上圆的凸包算法 我们之前探讨过这个有趣的问题: 平面上有若干圆,求包含这些圆的所有凸集的交. 根据之前讨论的结果,直接按圆心排序做扫描线的方法是错误的.我们需要考虑圆上的每一个点是否可以作为凸包上的一部分. 然而圆上的点的数目是无限多的.我们需要借助离散化的思想:因为我们发现凸包一定是由若干圆弧和线段构成的.而其中线段一定是切线段.由此,我们只需要将每两两圆的切点取出来求一个凸包.显然,在圆凸包上出现的切线段一定会在切点凸包中出现:而切点凸包中其余的线段则一定是弧弦. 但是,这个算法需要枚举

(模板)poj1113(graham扫描法求凸包)

题目链接:https://vjudge.net/problem/POJ-1113 题意:简化下题意即求凸包的周长+2×PI×r. 思路:用graham求凸包,模板是kuangbin的. AC code: #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int maxn=1005; const double PI=

如何防范算法求逆

假如您不幸遇到对Win32应用环境有足够了解的对手,以至于您的软件最终还是被凶悍的调试器任意蹂躏.但是您还远没有被打败,如果反调试技术(Anti-Debug)作为软件保护的第一道防线已经失守,您的对手只不过是掌握了一大堆汇编代码而已,毕竟代码和算法之间还是有相当距离的,所以您还有第二道防线可守--抗分析.在这道防线里,您有很多办法可以限制破解者掌握您的加密算法,从而阻止注册机或者破解补丁的出现. 一.前言 软件保护的目的是只向合法用户提供完整的功能,所以软件保护必然要包括验证用户合法性的环节,而

迪杰斯特拉算法求最短距离

头文件: #include <memory.h> #include <stdlib.h> #include <malloc.h> #include <string.h> #include ".\source\common.h" #include "lxbasic.h" #define MAX_VEX_NUM  20 #define MAX_STR_LEN  20 #define INFINITY  999  //无穷大

EM算法求高斯混合模型参数估计——Python实现

EM算法一般表述: 当有部分数据缺失或者无法观察到时,EM算法提供了一个高效的迭代程序用来计算这些数据的最大似然估计.在每一步迭代分为两个步骤:期望(Expectation)步骤和最大化(Maximization)步骤,因此称为EM算法. 假设全部数据Z是由可观测到的样本X={X1, X2,--, Xn}和不可观测到的样本Z={Z1, Z2,--, Zn}组成的,则Y = X∪Z.EM算法通过搜寻使全部数据的似然函数Log(L(Z; h))的期望值最大来寻找极大似然估计,注意此处的h不是一个变量