Convex Hull:O(n * log(n))算法 Graham Scan

本文介绍了一种基于GrahamScan算法实现的凸包构造方法。该算法首先按X坐标对顶点进行排序,之后分别构造上凸包与下凸包,并结合两者形成最终的凸包。文章详细展示了算法的具体实现过程。

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

课程:计算几何
书籍:计算几何:算法与应用

具体思路请自行观看上述的课程。
这里具体讲一下顶点集的排序:
我们通过X轴从大到小排序,然后运用Graham Scan算法可以得出构成上凸包的顶点。
然后逆序顶点顺序,运用Graham Scan算法可以得出构成下凸包的顶点。
结合两者,去掉重复点,即可得到构成整个凸包的顶点。


Point.h与之前一样

Main.cpp

/*2018/07/03 indere  Convex Hull
* 时间复杂度为Nlog(N)的算法思路: Graham Scan
*
*输入:多个顶点。
*输出:构成凸包的极点
*/

/*
10
7 9
-8 -1
-3 -1
1 4
-3 9
6 -4
7 5
6 6
-6 10
0 8
*/


#include "Point.h"
#include<vector>
using namespace std;

Point *points;
int pointsize;
Point *sortpoints;

void Initialize();                                      //初始化points数组
void UpSort(Point* points,int beign, int pointsize);    //根据X坐标从大到小排序
int QSortByX(Point* points, int begin, int end);        //快速排序
void Swap(Point* p, int i, int j);                      //交换points中的两个元素
vector<Point> Create_Up_Down_CH(Point* points, int pointsize);  //构造上/下凸包
int  ToLeft(Point v1, Point v2, Point s);               //
void Reverse(Point* points, int pointsize);             //反转顶点顺序
void PrintVector(vector<Point> s, int begin, int end);

int main() {
    Initialize();

    int begin = 0;
    UpSort(points, begin, pointsize);

    vector<Point> up = Create_Up_Down_CH(points, pointsize);
    cout << "上凸包为:\n";
    PrintVector(up, 0, up.size());

    Reverse(points, pointsize);
    vector<Point> down = Create_Up_Down_CH(points, pointsize);
    cout << "下凸包为:\n";
    PrintVector(down, 0, down.size());

    cout << "凸包的极点为:\n";
    PrintVector(up, 0, up.size());
    PrintVector(down, 1, down.size() - 1);

    return 0;
}

void Initialize() {
    cin >> pointsize;
    points = new Point[pointsize];
    for (int i = 0; i < pointsize; i++) {
        float x, y;
        cin >> x >> y;
        points[i] = Point(i + 1, x, y);
    }
}

void UpSort(Point* points, int begin, int pointsize) {
    if (begin >= pointsize)
        return;
    int m = QSortByX(points, begin, pointsize);
    UpSort(points, begin, m);
    UpSort(points, m + 1, pointsize);
}

int QSortByX(Point* points, int begin, int end) {
    int i, j, temp;
    i = begin - 1; j = begin;
    for (; j < end; j++) {
        if (points[j].x >= points[end - 1].x) {
            Swap(points, ++i, j);
        }
    }
    return i;
}

void Swap(Point* p, int i, int j) {
    Point temp;
    temp = p[i];
    p[i] = p[j];
    p[j] = temp;
}

vector<Point> Create_Up_Down_CH(Point* points, int pointsize) {

    vector<Point>s;
    vector<Point>t; 
    if (pointsize < 3) {
        cout << "并不能构成凸包\n";
        return s;
    }
    for (int i = 0; i < 2; i++)
        s.push_back(points[i]);
    for (int i = pointsize - 1; i >= 2; i--)
        t.push_back(points[i]);


    while (t.size()) {
        if (s.size() == 1) {
            s.push_back(t.back());
            t.pop_back();
            continue;
        }
        int result = ToLeft(s[s.size() - 2], s[s.size() - 1], t.back());
        if (result == 1) {
            s.push_back(t.back());
            t.pop_back();
        }
        else {
            s.pop_back();
        }
    }

    return s;
}

int  ToLeft(Point v1, Point v2, Point s) {
    float result = (v2.x *s.y + v1.x * v2.y + v1.y * s.x)
        - (v1.y * v2.x + v1.x * s.y + v2.y * s.x);

    if (result > 0.0f)      //左侧
        return 1;
    if (result == 0.0f)     //共线
        return 2;
    if (result < 0.0f)      //右侧
        return -1;
}

void Reverse(Point* points, int pointsize) {
    Point temp;
    for (int i = 0; i < pointsize / 2; i++) {
        temp = points[i];
        points[i] = points[pointsize - 1 - i];
        points[pointsize - 1 - i] = temp;
    }
}

void PrintVector(vector<Point> s, int begin, int end) {
    for (; begin < end; begin++)
        cout << s[begin];
}

这里写图片描述
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值