Graham扫描凸包算法

凸包(Convex Hull)是包含给定点集合的最小凸多边形。凸包算法有多种实现方法,其中包括基于递增极角排序、Graham扫描、Jarvis步进法等。下面,我将提供一个简单的凸包算法实现,基于Graham扫描算法。

Graham扫描算法是一种用于求解平面点集的凸包问题的常见算法。凸包是包含给定点集合的最小凸多边形。Graham扫描算法的基本思想是通过选择一个特殊的起点,将点集按照极角排序,然后通过栈的操作来逐步构建凸包。

以下是Graham扫描算法的基本步骤:

  • 选择极点: 从给定的点集中选择一个极点作为起始点。通常选择最下面且最左边的点,以确保算法的稳定性。

  • 极角排序: 将其他所有点按照相对于极点的极角进行排序。极角可以使用反正切函数(atan2)计算。排序后的点集顺序将确定扫描过程中点的访问顺序。

  • 扫描过程: 从第三个点开始,按照排序后的顺序逐个处理每个点。对于每个点,检查它与栈顶两个点的转向关系(顺时针、逆时针或平行)。如果是逆时针,将该点压入栈;如果是顺时针或平行,则出栈,直到找到逆时针为止。这确保了最终栈中的点构成凸包。

  • 构建凸包: 扫描完成后,栈中的点就是凸包的顶点,它们按照逆时针方向排列。

Graham扫描算法的时间复杂度主要取决于对点的排序操作,通常为 O ( n log ⁡ n ) O(n\log n) O(nlogn),其中n是点的数量。该算法的优势在于其相对简单的实现和较好的性能。然而,需要注意的是,在特定情况下,例如存在大量共线点的情况下,算法的性能可能会有所下降。

import matplotlib.pyplot as plt
import math# 定义二维点的类
class Point:def __init__(self, x, y):self.x = xself.y = y# 计算极角
def polar_angle(p0, p):dx = p.x - p0.xdy = p.y - p0.yreturn math.atan2(dy, dx)# 判断三个点的转向关系
def orientation(p, q, r):val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y)if val == 0:return 0  # 平行return 1 if val > 0 else 2  # 顺时针或逆时针# Graham扫描算法
def convex_hull(points):n = len(points)if n < 3:print("Convex Hull requires at least 3 points.")return []# 寻找最下面且最左边的点作为极点pivot = min(range(n), key=lambda i: (points[i].y, points[i].x))points[0], points[pivot] = points[pivot], points[0]# 根据极角对其余点进行排序points[1:] = sorted(points[1:], key=lambda p: (polar_angle(points[0], p), p.x, p.y))# 构建凸包hull = [points[0], points[1]]for i in range(2, n):while len(hull) > 1 and orientation(hull[-2], hull[-1], points[i]) != 2:hull.pop()hull.append(points[i])return hull# 示例点集
points = [Point(0, 3), Point(1, 1), Point(2, 2), Point(4, 4), Point(0, 0), Point(1, 2), Point(3, 1), Point(3, 3)]# 计算凸包
convex_hull_points = convex_hull(points)# 绘制原始离散点
x_values = [point.x for point in points]
y_values = [point.y for point in points]
plt.scatter(x_values, y_values, color='blue', label='Original Points')# 绘制凸包
hull_x = [point.x for point in convex_hull_points]
hull_y = [point.y for point in convex_hull_points]
hull_x.append(convex_hull_points[0].x)  # 闭合凸包
hull_y.append(convex_hull_points[0].y)
plt.plot(hull_x, hull_y, color='red', linestyle='-', linewidth=2, label='Convex Hull')# 显示图例和图形
plt.legend()
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Convex Hull')
plt.grid(True)
plt.show()

在这里插入图片描述

#include <iostream>
#include <vector>
#include <algorithm>
#include <stack>// 定义二维点的结构体
struct Point {double x, y;// 构造函数Point(double _x, double _y) : x(_x), y(_y) {}// 用于排序的比较函数static bool compare(const Point& a, const Point& b) {return (a.y < b.y) || (a.y == b.y && a.x < b.x);}
};// 计算极角
double polarAngle(const Point& p0, const Point& p) {double dx = p.x - p0.x;double dy = p.y - p0.y;return atan2(dy, dx);
}// 判断三个点的转向关系
int orientation(const Point& p, const Point& q, const Point& r) {double val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);if (val == 0) return 0;  // 平行return (val > 0) ? 1 : 2; // 顺时针或逆时针
}// Graham扫描算法
std::vector<Point> convexHull(std::vector<Point>& points) {size_t n = points.size();if (n < 3) {std::cerr << "Convex Hull requires at least 3 points." << std::endl;return std::vector<Point>();}// 寻找最下面且最左边的点作为极点size_t pivot = 0;for (size_t i = 1; i < n; i++) {if (points[i].y < points[pivot].y || (points[i].y == points[pivot].y && points[i].x < points[pivot].x)) {pivot = i;}}// 将极点移到数组的第一个位置std::swap(points[0], points[pivot]);// 根据极角对其余点进行排序std::sort(points.begin() + 1, points.end(), [&points](const Point& a, const Point& b) {double angleA = polarAngle(points[0], a);double angleB = polarAngle(points[0], b);return (angleA < angleB) || (angleA == angleB && (a.x < b.x || (a.x == b.x && a.y < b.y)));});// 构建凸包std::vector<Point> hull;hull.push_back(points[0]);hull.push_back(points[1]);for (size_t i = 2; i < n; i++) {while (hull.size() > 1 && orientation(hull[hull.size() - 2], hull[hull.size() - 1], points[i]) != 2) {hull.pop_back();}hull.push_back(points[i]);}return hull;
}int main() {// 示例点集std::vector<Point> points = { {0, 3}, {1, 1}, {2, 2}, {4, 4}, {0, 0}, {1, 2}, {3, 1}, {3, 3} };// 计算凸包std::vector<Point> convexHullPoints = convexHull(points);// 输出凸包的点std::cout << "Convex Hull Points:" << std::endl;for (const auto& point : convexHullPoints) {std::cout << "(" << point.x << ", " << point.y << ")" << std::endl;}return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/624803.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

多级缓存架构(一)项目初始化

文章目录 一、项目克隆二、数据库准备三、项目工程准备 一、项目克隆 克隆此项目到本地 https://github.com/Xiamu-ssr/MultiCache 来到start目录下&#xff0c;分别有以下文件夹 docker&#xff1a;docker相关文件item-service&#xff1a;springboot项目 二、数据库准备 …

Ncast盈可视高清智能录播系统busiFacade RCE漏洞(CVE-2024-0305)

产品介绍 Ncast盈可视高清智能录播系统是一套新进的音视频录制和播放系统&#xff0c;旨在提供高质量&#xff0c;高清定制的录播功能。 漏洞描述 广州盈可视电子科技有限公司的高清智能录播系统存在信息泄露漏洞(CVE-2024-0305)&#xff0c;攻击者可通过该漏洞&#xff0c;…

Sectigo的DV通配符https

Sectigo是近些年发展比较快速的CA认证机构&#xff0c;为了提升审核效率&#xff0c;在全国成立了审核机构&#xff0c;亚太审核中心的成立加快了Sectigo旗下的https证书的审核速度。Sectigo的https证书可以为网站安全提供有力支持&#xff0c;从而保护网站信息安全。今天就随S…

3、深入解析Redis Cluster集群运维与核心原理

在今天的大规模分布式系统中&#xff0c;Redis Cluster已经成为了许多企业选择的分布式缓存方案之一。了解Redis Cluster的运维及核心原理对于确保系统的高可用性和性能至关重要。本文将深入探讨Redis Cluster集群的运维细节和核心原理&#xff0c;以帮助读者更好地理解和优化R…

【STM32】STM32学习笔记-MPU6050简介(32)

00. 目录 文章目录 00. 目录01. MPU6050简介02. MPU6050参数03. MPU6050硬件电路04. MPU6050框图05. MPU6050常用寄存器06. 附录 01. MPU6050简介 •MPU6050是一个6轴姿态传感器&#xff0c;可以测量芯片自身X、Y、Z轴的加速度、角速度参数&#xff0c;通过数据融合&#xff0…

网站监测工具的极与极,Site24x7 与百川云

今天我们聊聊我用 Site24x7 的感受。对于有网站监测有需求的站长们来说&#xff0c;Site24x7 确实是个很强大的应用。但是它与百川云网站监测完全不一样&#xff0c;百川云网站监测是适合用中小微企业的交互极简的saas 应用&#xff0c;Site24x7 完全是另一个极端&#xff0c;适…

datax关系数据库插件设计和实现解释

背景 DataX是一个异构数据源离线同步工具&#xff0c;致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定高效的数据同步功能。解决异构数据源同步问题&#xff0c;DataX将复杂的网状的同步链路变成了星型数据链路&#xff0…

勒索家族瞄准制造业,亚信安全发布《勒索家族和勒索事件监控报告》

本周态势快速感知 本周&#xff08;2024年第二期&#xff09;全球共监测到勒索事件37起&#xff0c;事件数量持续下降&#xff0c;降至近半年最低值。 lockbit3.0仍然是影响最严重的勒索家族&#xff1b;akira和bianlian恶意家族也是两个活动频繁的恶意家族&#xff0c;需要注…

KubeSphere 在 vsleem 的落地实践

作者&#xff1a;方忠&#xff0c;苏州威视通智能科技有限公司技术经理&#xff0c;开源技术爱好者&#xff0c;长期活跃于 dromara 开源社区并参与贡献。 公司介绍 公司简介 苏州威视通智能科技有限公司&#xff0c;是一家全球领先的全景 AI 平台提供商&#xff0c;结合极致…

1.15作业

使用计数型信号量设计&#xff1a;生产者和消费者模型 总结今天学习的API函数&#xff0c;写出函数参数和返回值的意思&#xff0c;并且说明函数功能 创建队列 osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_si…

Java项目:121SSM记账管理系统

博主主页&#xff1a;Java旅途 简介&#xff1a;分享计算机知识、学习路线、系统源码及教程 文末获取源码 一、项目介绍 记账管理系统基于SpringSpringMVCMybatis开发&#xff0c;系统主要功能如下&#xff1a; 收入项管理 支出项管理 收入方式管理 支出方式管理 添加收入…

《ORANGE’S:一个操作系统的实现》读书笔记(三十一)文件系统(六)

上一篇文章记录了对文件的读写操作&#xff0c;那么文件操作到目前为止&#xff0c;已经完成了创建和读写&#xff0c;还剩下的常用操作就是删除文件了。这篇文章就来记录删除文件的实现以及总结一下为文件系统添加系统调用的步骤。 删除文件 删除是添加的反过程&#xff0c;…

微服务自动化docker-compose

一、docker-compose介绍 Docker Compose是一个用来定义和运行多个复杂应用的Docker编排工具。例如&#xff0c;一个使用Docker容器的微服务项目&#xff0c;通常由多个容器应用组成。那么部署时如何快速启动各个微服务呢&#xff0c;一个个手动启动&#xff1f;假如有上百个微服…

计算机毕业设计 | SpringBoot+vue校园问卷调查系统(附源码)

1&#xff0c;绪论 研究目的 在进入21世纪以后&#xff0c;互联网得到了蓬勃的发展&#xff0c;电子问卷调查也开始逐渐流行起来。传统纸质问卷和电子问卷相比较后&#xff0c;传统问卷还存在很多弊端&#xff1a; 问卷分发起来比较困难&#xff0c;并且分发试卷耗费大量的金…

CSS 基本选择器 复合选择器

文章目录 基本选择器标记选择器类别选择器ID选择器测试基本选择器 复合选择器交集选择器并集选择器后代选择器全选选择器测试复合选择器 基本选择器 准备几个HTML标签用来测试 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"U…

智能小程序能做什么?

一. 自定义Tab页 涂鸦提供了丰富的场景化、个性化的 ToC 智能服务&#xff0c;不仅可以快速低成本的自由搭建出更多智能服务&#xff0c;还为你提供了基于小程序技术方案的可自主可控的自定义开发链路&#xff0c;为拓展更多品牌化、个性化、差异化智能服务提供生态基础。 我…

Javaweb之SpringBootWeb案例的详细解析

SpringBootWeb案例 前面我们已经讲解了Web前端开发的基础知识&#xff0c;也讲解了Web后端开发的基础(HTTP协议、请求响应)&#xff0c;并且也讲解了数据库MySQL&#xff0c;以及通过Mybatis框架如何来完成数据库的基本操作。 那接下来&#xff0c;我们就通过一个案例&#xf…

word无法插入方程式(方程式反灰)

word无法插入方程式&#xff08;方程式反灰&#xff09; 来自实测>插入方程式&#xff0c;反灰用不了>随便存在哪里&#xff0c;右键看属性&#xff1a;>发现真的是doc&#xff0c;得改成docx才可以&#xff1a;>打开原始档案&#xff0c;另存为word文件即可&#…

什么是google算法?

谷歌算法本身指的是谷歌针对搜索引擎做的规定 要想在别人的地盘玩&#xff0c;那肯定要了解这个地盘的规定&#xff0c;不然做了什么违反了规定&#xff0c;谷歌肯定不会让你继续玩下去 要想做谷歌&#xff0c;那肯定要了解谷歌的算法&#xff0c;然而谷歌的算法也不是一成不变…

ros2 基础学习04 -colcon构建工具

一、colcon构建工具介绍 1.1 构建系统与构建工具 构建系统与构建工具区分点在于针对的对象不同&#xff0c;构建系统只针对一个单独的包进行构建&#xff0c;而构建工具重点在于按照依赖关系依次调用构建系统完成一系列功能包的构建。 1.2 构建系统 构建系统包括CMake、Pyt…