凸包问题-Graham-Scan算法-python实现
一般来说凸包问题有三种解决方式:蛮力法、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实现相关推荐
- 计算几何--凸包之graham scan算法
Graham scan算法主要步骤: 找出所有已知点的y值最小,如果相同,取x值最小的点,作为基准点s. 以s为基准,所有的点按照与X轴夹角从小到大排序. 使用两个栈,一个记录已访问的点,一个记录未访 ...
- 凸包Graham Scan算法实现
凸包Graham Scan算法实现 凸包算法实现点集合中搜索凸包顶点的功能,可以处理共线情况,可以输出共线点也可以不输出而只输出凸包顶点.经典的Graham Scan算法,点排序使用极角排序方式,并对 ...
- graham算法 java_凸包Graham Scan算法实现
凸包算法实现点集合中搜索凸包顶点的功能,可以处理共线情况,可以输出共线点也可以不输出而只输出凸包顶点.经典的Graham Scan算法,点排序使用极角排序方式,并对共线情况做特殊处理.一般算法是将共线 ...
- 计算几何入门 1.6:凸包的构造——Graham Scan算法
上文简要分析出了凸包构造问题算法的下界:O(nlogn),在此就引入一种下界意义上最优的算法:Graham Scan算法.这种算法可以保证在最坏情况下时间复杂度也不超过nlogn.我们先大致了解一下算 ...
- Graham Scan算法
预备知识:凸集:集合S中任意两点的连线都在集合S中,如果简单的理解,可以理解为凸边形 凸包:对于给定集合X,所有包含X的凸集的交集,简单的理解,就是包含X的最小凸集,或者就是最外圈的点连起来 极角排序 ...
- Graham Scan凸包算法
获得凸包的算法可以算是计算几何中最基础的算法之一了.寻找凸包的算法有很多种,Graham Scan算法是一种十分简单高效的二维凸包算法,能够在O(nlogn)的时间内找到凸包. 首先介绍一下二维向量的 ...
- Python:实现graham scan葛立恒扫描法算法(附完整源码)
Python:实现graham scan葛立恒扫描法算法 from __future__ import annotations from collections import deque from e ...
- 点集凸包算法python实现(二)
算法逻辑 在点集凸包算法python实现这篇博客中介绍了一种凸包算法,这种算法中凸包点搜索的过程较为麻烦,主要是因为计算点集连线与X轴的夹角需要考虑到四个不同象限,在这里通过计算向量夹角的方式,对凸包 ...
- 【计算几何】凸包之graham算法(适合小白)
计算几何–凸包(graham算法实现) 题目链接:LeetCode587 https://leetcode-cn.com/problemset/all/ 题目描述 在一个二维的花园中,有一些用 (x, ...
最新文章
- 骁龙855在AI性能上真的秒杀麒麟980?噱头而已
- Object-c:NSString的创建
- python之路——迭代器和生成器
- python爬虫哪个选择器好用_Python网络爬虫四大选择器用法原理总结
- MySQL回闪_MySQL进行BINLOG回闪
- rsa前后端加密流程_不懂前后端分离?这篇就够了
- 上下相机贴合对位计算公式_深圳贴合机生产家介绍;真空贴合机这些产品功能你了解多少...
- Chrome 插件开发与本地程序交互流程
- Eclipse+Tomcat+MAVEN+SVN项目完整环境搭建
- nodeJS之域名DNS
- 你知道怎么解决DB读写分离,导致数据不一致问题吗?
- xiaomi 2C android root,小米MIX2如何ROOT?小米MIX2一键Root图文教程
- Python的缩进问题unindent does not match any outer indentation level
- 计算机win10无法打开小键盘,win10数字小键盘开机不启动解决方法
- 关于BandiZip的bug,linux解压下不友好情况
- 使用Dev C++运行c语言代码时碰到Failed to executeC:\c++.cpp: Error 0 :操作成功完成
- 电磁场仿真试验【Matlab】电磁波极化仿真
- ios中头文件交叉导入问题
- 优化算法(二)遗传算法及python实现
- [导入]推荐一个好网站