凸包算法实现点集合中搜索凸包顶点的功能,可以处理共线情况,可以输出共线点也可以不输出而只输出凸包顶点。经典的Graham Scan算法,点排序使用极角排序方式,并对共线情况做特殊处理。一般算法是将共线的点去掉距离小的,保留最远的,这样处理会导致不能输出凸包边上的点,只能输出顶点。但是有时候需要输出这些边上的点,因此这里我将共线点都保留,并按照顺序排列。共线点排列方式是:非起始边按照从远道近排列,起始边按从近到远排列。

算法原理参见如下网址,讲解很详细:

http://softsurfer.com/Archive/algorithm_0109/algorithm_0109.htm

实现如下:

#include <iostream>

#include <math.h>

using namespace std;

typedef struct{double x,y;} Point;

void qsortpoint(Point s[],Point base,int start,int end);

void sortstartedge(Point s[],int nums);

//向量(x1,y1),(x2,y2)的叉积

double CrossMul(double x1,double y1,double x2,double y2)

{

    return x1*y2-x2*y1;

}

//向量(x1,y1),(x2,y2)的点积

double DotMul(double x1,double y1,double x2,double y2)

{

    return x1*x2+y1*y2;

}

//跨立判断

//判断点c是在向量ab的逆时针方向还是顺时针方向,大于零逆时针,等于0则共线

double CrossMul(Point a,Point b,Point c)

{

    return CrossMul(b.x-a.x,b.y-a.y,c.x-a.x,c.y-a.y);

}

//计算向量ab和ac点积

double DotMul(Point a,Point b,Point c)

{

    return DotMul(b.x-a.x,b.y-a.y,c.x-a.x,c.y-a.y);

}

//判断浮点数符号

int doublecmp(double d)

{

    if(fabs(d)<10e-6)

        return 0;

    return d>0?1:-1;

}

//判断同一直线上的三个点位置,点c是否在点ab之间

bool betweenCmp(Point a,Point b,Point c)

{

    if(doublecmp(DotMul(c,a,b))<=0)

        return true;

    return false;

}

//判断j是否在base->i向量的左边或当共线时j是否位于它们的线段之间

bool isLeftorNearer(Point base,Point i,Point j)

{

    if(CrossMul(base,i,j)>0)

        return true;

    if(CrossMul(base,i,j)==0 && betweenCmp(base,i,j))

        return true;

    return false;

}

void swap(Point& a,Point& b)

{

    Point temp = b;

    b=a;

    a=temp;

}

//以s中的最低点为参考点,对其他所有点进行极角排序(逆时针)

//共线时离参考点较远的点排在前面,凸包的起始边共线点从近到远排列

void sortpoint(Point s[],int nums)

{

    //找最低点

    for(int i=1;i<nums;i++)

    {

        if(s[i].y<s[0].y || (s[i].y==s[0].y && s[i].x<s[0].x))

            swap(s[0],s[i]);

    }

    qsortpoint(s,s[0],1,nums);

    //将起始边上的共线点重新排列

    sortstartedge(s,nums);

}

void sortstartedge(Point s[],int nums)

{

    int i,j;

    for(i=2;i<nums;i++)

    {

        if(CrossMul(s[0],s[1],s[i])!=0)

            break;

    }

    for(j=1;j<(i+1)/2;j++)

        swap(s[j],s[i-j]);

}

//将点按极角逆时针排序

void qsortpoint(Point s[],Point base,int start,int end)

{

    if(start>=end)

        return;

    Point partition = s[end-1];

    int i=start-1,j=start-1;

    while(++j<end-1)

    {

        if(isLeftorNearer(base,s[j],partition))

        {

            swap(s[++i],s[j]);

        }

    }

    swap(s[++i],s[end-1]);

    qsortpoint(s,base,start,i);

    qsortpoint(s,base,i+1,end);

}

void ConvexHull(Point s[],int nums,Point result[],int& resultnums)

{

    sortpoint(s,nums);

resultnums = 0;

    if(nums<=3)

    {

        for(int i=0;i<nums;i++)

            result[resultnums++] = s[i];

        return;

    }

    int top=0;

    int i;

    for(i=0;i<2;i++)

        result[top++] = s[i];

    while(i<nums)

    {

        //用<号判断则包含凸包边上的共线点,<=号判断则只包含凸包顶点

        if(CrossMul(result[top-2],result[top-1],s[i])<=0)

        {

            top--;

        }

        else

        {

            result[top++] = s[i++];

        }

    }

    //最后加入起点形成闭包

    while(CrossMul(result[top-2],result[top-1],s[0])<=0)

    {

        top--;

    }

    result[top++]=s[0];

    resultnums = top;

}

int main()

{

    Point pa[] = {{0,0},{1,0},{2,0},{3,0},{4,0},

                {4,1},{4,2},{4,3},{4,4},

                {3,4},{2,4},{1,4},{0,4},

                {0,3},{0,2},{0,1},{2,2},{1,1}};



    cout<<"convex hull is:"<<endl;

    Point result[18];

    int nums;

    ConvexHull(pa,18,result,nums);

    for(int i=0;i<nums;i++)

        cout<<result[i].x <<"," <<result[i].y<<endl;

    return 0;

}

经验证,算法无误。

凸包Graham Scan算法实现的更多相关文章

  1. 二维凸包 Graham扫描算法

    题目链接: http://poj.org/problem?id=1113 求下列点的凸包 求得凸包如下: Graham扫描算法: 找出最左下的点,设为一号点,将其它点对一号点连线,按照与x轴的夹角大小 ...

  2. Graham Scan凸包算法

    获得凸包的算法可以算是计算几何中最基础的算法之一了.寻找凸包的算法有很多种,Graham Scan算法是一种十分简单高效的二维凸包算法,能够在O(nlogn)的时间内找到凸包. 首先介绍一下二维向量的 ...

  3. 凸包问题 Graham Scan

    2020-01-09 15:14:21 凸包问题是计算几何的核心问题,并且凸包问题的研究已经持续了好多年,这中间涌现出了一大批优秀的算法. 凸包问题的最优解法是Graham Scan算法,该算法可以保 ...

  4. 凸包问题——Graham Scan

    Graham Scan 概述: 对于凸多边形的定义不在这里做详细叙述,这里给出算法的实现原理. Step 1: 找出x值最小的点的集合,从其中找出y值最小的点作为初始点 Step 2: 获得新序列后, ...

  5. POJ 2187 旋转卡壳 + 水平序 Graham 扫描算法 + 运算符重载

    水平序 Graham 扫描算法: 计算二维凸包的时候可以用到,Graham 扫描算法有水平序和极角序两种. 极角序算法能一次确定整个凸包, 但是计算极角需要用到三角函数,速度较慢,精度较差,特殊情况较 ...

  6. 计算几何 二维凸包问题 Andrew算法

    凸包:把给定点包围在内部的.面积最小的凸多边形. Andrew算法是Graham算法的变种,速度更快稳定性也更好. 首先把全部点排序.依照第一keywordx第二keywordy从小到大排序,删除反复 ...

  7. 磁盘寻道时间算法之----------------SCAN算法和最短寻道时间优先调度算法

    若干个等待访问磁盘者依次要访问的柱面编号为:80,40,74,14,60,31,61,假设每移动一个柱面需要4毫秒时间,移动到当前位于35号柱面,且当前的移动方向向柱面号增加的方向.请计算: (1)若 ...

  8. HDU 5928 DP 凸包graham

    给出点集,和不大于L长的绳子,问能包裹住的最多点数. 考虑每个点都作为左下角的起点跑一遍极角序求凸包,求的过程中用DP记录当前以j为当前末端为结束的的最小长度,其中一维作为背包的是凸包内侧点的数量.也 ...

  9. 【计算几何】二维凸包——Graham's Scan法

    凸包 点集Q的凸包(convex hull)是指一个最小凸多边形,满足Q中的点或者在多边形边上或者在其内.右图中由红色线段表示的多边形就是点集Q={p0,p1,...p12}的凸包. 一组平面上的点, ...

随机推荐

  1. sql分页查询(2005以后的数据库)和access分页查询

    sql分页查询: select * from ( select ROW_NUMBER() over(order by 排序条件) as rowNumber,* from [表名] where 条件 ) ...

  2. 中断或取消Promise链的可行方案

    ES6标准引入的异步编程解决方案Promise,能够将层层嵌套的回调转化成扁平的Promise链式调用,优雅地解决了“回调地狱”的问题.当Promise链中抛出一个错误时,错误信息沿着链路向后传递,直 ...

  3. vue中 localStorage的使用方法(详解)

    vue中实现本地储存的方法:localStorage,在HTML5中,新加入了一个localStorage特性,这个特性主要是用来作为本地存储来使用的,解决了cookie存储空间不足的问题(cooki ...

  4. 实际应用脚本备份1——Ubuntu下应用升级脚本与执行方法

    程序自动更新脚本,命名为makefile: build:run run: killall java /webapps/‘应用目录名’/ /webapps/ ‘应用目录名’/ cd /opt/apach ...

  5. unbutu apt-get update失败及解决办法

    今天在用apt-get update更新时一直失败,报的错误为”Failed to fetch 404 Not Found”,因为我的镜像改为了mirrors.aliyun.com 我试着ping了一 ...

  6. python+Appium自动化:Appium-desktop界面简介

    Appium Desktop是一款适用于Mac,Windows和Linux的开源应用程序,提供了更加优化的图形界面. Appium Desktop是由Simple.Advanced.Presets三个 ...

  7. solr 查询解析器

    定义 查询解析器用于将查询语句(q参数)解析成搜索语法. 默认解析器:lucene Solr在查询的时候,用到了QueryParser对用户输入做解析,solr默认使用的解析器是lucene,被称之为 ...

  8. 基于Hexo的个人博客搭建(下)

    5.服务器端测试 —5.1 clone到/var/www/html git clone /home/git/repos/myblog.git /var/www/html chown -R  git:g ...

  9. Httpd总结 :HTTPD的基本概念

    这是一篇为初学者准备的文章,所以作者会尽量从基础出发,尽量细致的描述每一个细节,以求让初学者不会一头雾水,有一定基础的同学就不用看了,以免浪费你的时间.   假设博主今天春心荡漾,想要访问一些不可描述 ...

  10. 一步一步带你安装史上最难安装的 vim 插件

    YouCompleteMe is a fast, as-you-type, fuzzy-search code completion engine for Vim.参考: https://github ...