一般来说凸包问题有三种解决方式:蛮力法、Graham-Scan法和分治法。关于蛮力法和分治法的python实现可参考博文:蛮力法、分治法,博主写的很清晰。

这里主要介绍Graham-Scan算法的实现,网上的Graham-Scan算法python实现很多,如这篇博文,原理和实现都很清晰,但是当时使用这个程序测试很大的数据量(如超过1000个点以上)时会报如下错误。

程序报错说栈空,应该是数据点很多的时候多点共线,栈内元素连续弹出,因此基于这篇博文改了一些代码(主要是103行和104行),实现代码如下:

import matplotlib.pyplot as plt
import math
import time
import numpy as npstart_t = time.clock()# points中纵坐标最小点的索引,若有多个则返回横坐标最小的点
def get_bottom_point(points):min_index = 0n = len(points)for i in range(0, n):if points[i][1] < points[min_index][1] or (points[i][1] == points[min_index][1] and points[i][0] < points[min_index][0]):min_index = ireturn min_index# 按照与中心点的极角进行排序,余弦,center_point: 中心点
def sort_polar_angle_cos(points, center_point):n = len(points)cos_value = []rank = []norm_list = []for i in range(0, n):point_ = points[i]point = [point_[0] - center_point[0], point_[1] - center_point[1]]rank.append(i)norm_value = math.sqrt(point[0] * point[0] + point[1] * point[1])norm_list.append(norm_value)if norm_value == 0:cos_value.append(1)else:cos_value.append(point[0] / norm_value)for i in range(0, n - 1):index = i + 1while index > 0:if cos_value[index] > cos_value[index - 1] or (cos_value[index] == cos_value[index - 1]and norm_list[index] > norm_list[index - 1]):temp = cos_value[index]temp_rank = rank[index]temp_norm = norm_list[index]cos_value[index] = cos_value[index - 1]rank[index] = rank[index - 1]norm_list[index] = norm_list[index - 1]cos_value[index - 1] = temprank[index - 1] = temp_ranknorm_list[index - 1] = temp_normindex = index - 1else:breaksorted_points = []for i in rank:sorted_points.append(points[i])return sorted_points# 返回向量与向量[1, 0]之间的夹角-从[1, 0]沿逆时针方向旋转多少度能到达这个向量
def vector_angle(vector):norm_ = math.sqrt(vector[0] * vector[0] + vector[1] * vector[1])if norm_ == 0:return 0angle = math.acos(vector[0] / norm_)if vector[1] >= 0:return angleelse:return 2 * math.pi - angle# 两向量的叉乘
def coss_multi(v1, v2):return v1[0] * v2[1] - v1[1] * v2[0]def graham_scan(points):bottom_index = get_bottom_point(points)bottom_point = points.pop(bottom_index)sorted_points = sort_polar_angle_cos(points, bottom_point)m = len(sorted_points)if m < 2:print("点的数量过少,无法构成凸包")returnstack = []stack.append(bottom_point)stack.append(sorted_points[0])stack.append(sorted_points[1])# print('当前stack', stack)for i in range(2, m):length = len(stack)top = stack[length - 1]next_top = stack[length - 2]v1 = [sorted_points[i][0] - next_top[0], sorted_points[i][1] - next_top[1]]v2 = [top[0] - next_top[0], top[1] - next_top[1]]while coss_multi(v1, v2) >= 0:if length < 3:     # 加上这两行代码之后,数据量很大时不会再报错break          # 加上这两行代码之后,数据量很大时不会再报错stack.pop()length = len(stack)top = stack[length - 1]next_top = stack[length - 2]v1 = [sorted_points[i][0] - next_top[0], sorted_points[i][1] - next_top[1]]v2 = [top[0] - next_top[0], top[1] - next_top[1]]stack.append(sorted_points[i])return stack# 产生随机点
n_iter = [100, 500, 1000, 2000, 3000]
time_cost = []
for n in n_iter:points = []for i in range(n):point_x = np.random.randint(1, 100)point_y = np.random.randint(1, 100)temp = np.hstack((point_x, point_y))point = temp.tolist()points.append(point)result = graham_scan(points)# 记录程序运行时间end_t = time.clock()time_iter = end_t - start_tprint("Graham-Scan算法运行时间:", time_iter)# draw(list_points, border_line)time_cost.append(time_iter)# 画结果图"""for point in points:plt.scatter(point[0], point[1], marker='o', c='y', s=8)length = len(result)for i in range(0, length - 1):plt.plot([result[i][0], result[i + 1][0]], [result[i][1], result[i + 1][1]], c='r')plt.plot([result[0][0], result[length - 1][0]], [result[0][1], result[length - 1][1]], c='r')plt.show()"""# 不同测试集下的运行时间
plt.plot(n_iter, time_cost)
plt.show()

运行之后的性能图如下
3000个点时返回的凸包如下

凸包问题-Graham-Scan算法-python实现相关推荐

  1. 计算几何--凸包之graham scan算法

    Graham scan算法主要步骤: 找出所有已知点的y值最小,如果相同,取x值最小的点,作为基准点s. 以s为基准,所有的点按照与X轴夹角从小到大排序. 使用两个栈,一个记录已访问的点,一个记录未访 ...

  2. 凸包Graham Scan算法实现

    凸包Graham Scan算法实现 凸包算法实现点集合中搜索凸包顶点的功能,可以处理共线情况,可以输出共线点也可以不输出而只输出凸包顶点.经典的Graham Scan算法,点排序使用极角排序方式,并对 ...

  3. graham算法 java_凸包Graham Scan算法实现

    凸包算法实现点集合中搜索凸包顶点的功能,可以处理共线情况,可以输出共线点也可以不输出而只输出凸包顶点.经典的Graham Scan算法,点排序使用极角排序方式,并对共线情况做特殊处理.一般算法是将共线 ...

  4. 计算几何入门 1.6:凸包的构造——Graham Scan算法

    上文简要分析出了凸包构造问题算法的下界:O(nlogn),在此就引入一种下界意义上最优的算法:Graham Scan算法.这种算法可以保证在最坏情况下时间复杂度也不超过nlogn.我们先大致了解一下算 ...

  5. Graham Scan算法

    预备知识:凸集:集合S中任意两点的连线都在集合S中,如果简单的理解,可以理解为凸边形 凸包:对于给定集合X,所有包含X的凸集的交集,简单的理解,就是包含X的最小凸集,或者就是最外圈的点连起来 极角排序 ...

  6. Graham Scan凸包算法

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

  7. Python:实现graham scan葛立恒扫描法算法(附完整源码)

    Python:实现graham scan葛立恒扫描法算法 from __future__ import annotations from collections import deque from e ...

  8. 点集凸包算法python实现(二)

    算法逻辑 在点集凸包算法python实现这篇博客中介绍了一种凸包算法,这种算法中凸包点搜索的过程较为麻烦,主要是因为计算点集连线与X轴的夹角需要考虑到四个不同象限,在这里通过计算向量夹角的方式,对凸包 ...

  9. 【计算几何】凸包之graham算法(适合小白)

    计算几何–凸包(graham算法实现) 题目链接:LeetCode587 https://leetcode-cn.com/problemset/all/ 题目描述 在一个二维的花园中,有一些用 (x, ...

最新文章

  1. 骁龙855在AI性能上真的秒杀麒麟980?噱头而已
  2. Object-c:NSString的创建
  3. python之路——迭代器和生成器
  4. python爬虫哪个选择器好用_Python网络爬虫四大选择器用法原理总结
  5. MySQL回闪_MySQL进行BINLOG回闪
  6. rsa前后端加密流程_不懂前后端分离?这篇就够了
  7. 上下相机贴合对位计算公式_深圳贴合机生产家介绍;真空贴合机这些产品功能你了解多少...
  8. Chrome 插件开发与本地程序交互流程
  9. Eclipse+Tomcat+MAVEN+SVN项目完整环境搭建
  10. nodeJS之域名DNS
  11. 你知道怎么解决DB读写分离,导致数据不一致问题吗?
  12. xiaomi 2C android root,小米MIX2如何ROOT?小米MIX2一键Root图文教程
  13. Python的缩进问题unindent does not match any outer indentation level
  14. 计算机win10无法打开小键盘,win10数字小键盘开机不启动解决方法
  15. 关于BandiZip的bug,linux解压下不友好情况
  16. 使用Dev C++运行c语言代码时碰到Failed to executeC:\c++.cpp: Error 0 :操作成功完成
  17. 电磁场仿真试验【Matlab】电磁波极化仿真
  18. ios中头文件交叉导入问题
  19. 优化算法(二)遗传算法及python实现
  20. [导入]推荐一个好网站

热门文章

  1. 萧萧雨落情未绝,瑟瑟风起愁又涌
  2. springboot 佛祖保佑,永无bug
  3. 课时31:永久储存:腌制一缸美味的泡菜
  4. 因果,稳定,无源,无损系统(1)
  5. VirtualBox用 PQ与Fdisk 激活主分区(图解) 用于解决硬盘无法引导系统
  6. 怎么查看电脑内存的型号
  7. 钢材表面缺陷检测分类不同图像增强方式的对比研究
  8. C#正则查找字符串是否包含字母
  9. 计算机在职研究生的详细介绍
  10. 全网唯一正确身份证和社统一社会信用代码自定义表单校验器(身份证校验和社统一社会信用代码校验)