mirror of
https://github.com/TheAlgorithms/Python.git
synced 2025-04-08 06:45:54 +00:00
Reduce the complexity of other/graham_scan.py (#7953)
* Reduce the complexity of other/graham_scan.py * Lower the --max-complexity threshold in the file .flake8 * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix tests * Update other/graham_scan.py Co-authored-by: Christian Clauss <cclauss@me.com> * Update graham_scan.py * Update other/graham_scan.py Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Christian Clauss <cclauss@me.com>
This commit is contained in:
parent
a02de964d1
commit
978414bd50
2
.flake8
2
.flake8
@ -1,7 +1,7 @@
|
|||||||
[flake8]
|
[flake8]
|
||||||
max-line-length = 88
|
max-line-length = 88
|
||||||
# max-complexity should be 10
|
# max-complexity should be 10
|
||||||
max-complexity = 20
|
max-complexity = 19
|
||||||
extend-ignore =
|
extend-ignore =
|
||||||
# Formatting style for `black`
|
# Formatting style for `black`
|
||||||
E203 # Whitespace before ':'
|
E203 # Whitespace before ':'
|
||||||
|
@ -14,6 +14,82 @@ from math import atan2, degrees
|
|||||||
from sys import maxsize
|
from sys import maxsize
|
||||||
|
|
||||||
|
|
||||||
|
# traversal from the lowest and the most left point in anti-clockwise direction
|
||||||
|
# if direction gets right, the previous point is not the convex hull.
|
||||||
|
class Direction(Enum):
|
||||||
|
left = 1
|
||||||
|
straight = 2
|
||||||
|
right = 3
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"{self.__class__.__name__}.{self.name}"
|
||||||
|
|
||||||
|
|
||||||
|
def angle_comparer(point: tuple[int, int], minx: int, miny: int) -> float:
|
||||||
|
"""Return the angle toward to point from (minx, miny)
|
||||||
|
|
||||||
|
:param point: The target point
|
||||||
|
minx: The starting point's x
|
||||||
|
miny: The starting point's y
|
||||||
|
:return: the angle
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
>>> angle_comparer((1,1), 0, 0)
|
||||||
|
45.0
|
||||||
|
|
||||||
|
>>> angle_comparer((100,1), 10, 10)
|
||||||
|
-5.710593137499642
|
||||||
|
|
||||||
|
>>> angle_comparer((5,5), 2, 3)
|
||||||
|
33.690067525979785
|
||||||
|
"""
|
||||||
|
# sort the points accorgind to the angle from the lowest and the most left point
|
||||||
|
x, y = point
|
||||||
|
return degrees(atan2(y - miny, x - minx))
|
||||||
|
|
||||||
|
|
||||||
|
def check_direction(
|
||||||
|
starting: tuple[int, int], via: tuple[int, int], target: tuple[int, int]
|
||||||
|
) -> Direction:
|
||||||
|
"""Return the direction toward to the line from via to target from starting
|
||||||
|
|
||||||
|
:param starting: The starting point
|
||||||
|
via: The via point
|
||||||
|
target: The target point
|
||||||
|
:return: the Direction
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
>>> check_direction((1,1), (2,2), (3,3))
|
||||||
|
Direction.straight
|
||||||
|
|
||||||
|
>>> check_direction((60,1), (-50,199), (30,2))
|
||||||
|
Direction.left
|
||||||
|
|
||||||
|
>>> check_direction((0,0), (5,5), (10,0))
|
||||||
|
Direction.right
|
||||||
|
"""
|
||||||
|
x0, y0 = starting
|
||||||
|
x1, y1 = via
|
||||||
|
x2, y2 = target
|
||||||
|
via_angle = degrees(atan2(y1 - y0, x1 - x0))
|
||||||
|
via_angle %= 360
|
||||||
|
target_angle = degrees(atan2(y2 - y0, x2 - x0))
|
||||||
|
target_angle %= 360
|
||||||
|
# t-
|
||||||
|
# \ \
|
||||||
|
# \ v
|
||||||
|
# \|
|
||||||
|
# s
|
||||||
|
# via_angle is always lower than target_angle, if direction is left.
|
||||||
|
# If they are same, it means they are on a same line of convex hull.
|
||||||
|
if target_angle > via_angle:
|
||||||
|
return Direction.left
|
||||||
|
elif target_angle == via_angle:
|
||||||
|
return Direction.straight
|
||||||
|
else:
|
||||||
|
return Direction.right
|
||||||
|
|
||||||
|
|
||||||
def graham_scan(points: list[tuple[int, int]]) -> list[tuple[int, int]]:
|
def graham_scan(points: list[tuple[int, int]]) -> list[tuple[int, int]]:
|
||||||
"""Pure implementation of graham scan algorithm in Python
|
"""Pure implementation of graham scan algorithm in Python
|
||||||
|
|
||||||
@ -57,86 +133,12 @@ def graham_scan(points: list[tuple[int, int]]) -> list[tuple[int, int]]:
|
|||||||
# remove the lowest and the most left point from points for preparing for sort
|
# remove the lowest and the most left point from points for preparing for sort
|
||||||
points.pop(minidx)
|
points.pop(minidx)
|
||||||
|
|
||||||
def angle_comparer(point: tuple[int, int], minx: int, miny: int) -> float:
|
|
||||||
"""Return the angle toward to point from (minx, miny)
|
|
||||||
|
|
||||||
:param point: The target point
|
|
||||||
minx: The starting point's x
|
|
||||||
miny: The starting point's y
|
|
||||||
:return: the angle
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
>>> angle_comparer((1,1), 0, 0)
|
|
||||||
45.0
|
|
||||||
|
|
||||||
>>> angle_comparer((100,1), 10, 10)
|
|
||||||
-5.710593137499642
|
|
||||||
|
|
||||||
>>> angle_comparer((5,5), 2, 3)
|
|
||||||
33.690067525979785
|
|
||||||
"""
|
|
||||||
# sort the points accorgind to the angle from the lowest and the most left point
|
|
||||||
x = point[0]
|
|
||||||
y = point[1]
|
|
||||||
angle = degrees(atan2(y - miny, x - minx))
|
|
||||||
return angle
|
|
||||||
|
|
||||||
sorted_points = sorted(points, key=lambda point: angle_comparer(point, minx, miny))
|
sorted_points = sorted(points, key=lambda point: angle_comparer(point, minx, miny))
|
||||||
# This insert actually costs complexity,
|
# This insert actually costs complexity,
|
||||||
# and you should instead add (minx, miny) into stack later.
|
# and you should instead add (minx, miny) into stack later.
|
||||||
# I'm using insert just for easy understanding.
|
# I'm using insert just for easy understanding.
|
||||||
sorted_points.insert(0, (minx, miny))
|
sorted_points.insert(0, (minx, miny))
|
||||||
|
|
||||||
# traversal from the lowest and the most left point in anti-clockwise direction
|
|
||||||
# if direction gets right, the previous point is not the convex hull.
|
|
||||||
class Direction(Enum):
|
|
||||||
left = 1
|
|
||||||
straight = 2
|
|
||||||
right = 3
|
|
||||||
|
|
||||||
def check_direction(
|
|
||||||
starting: tuple[int, int], via: tuple[int, int], target: tuple[int, int]
|
|
||||||
) -> Direction:
|
|
||||||
"""Return the direction toward to the line from via to target from starting
|
|
||||||
|
|
||||||
:param starting: The starting point
|
|
||||||
via: The via point
|
|
||||||
target: The target point
|
|
||||||
:return: the Direction
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
>>> check_direction((1,1), (2,2), (3,3))
|
|
||||||
Direction.straight
|
|
||||||
|
|
||||||
>>> check_direction((60,1), (-50,199), (30,2))
|
|
||||||
Direction.left
|
|
||||||
|
|
||||||
>>> check_direction((0,0), (5,5), (10,0))
|
|
||||||
Direction.right
|
|
||||||
"""
|
|
||||||
x0, y0 = starting
|
|
||||||
x1, y1 = via
|
|
||||||
x2, y2 = target
|
|
||||||
via_angle = degrees(atan2(y1 - y0, x1 - x0))
|
|
||||||
if via_angle < 0:
|
|
||||||
via_angle += 360
|
|
||||||
target_angle = degrees(atan2(y2 - y0, x2 - x0))
|
|
||||||
if target_angle < 0:
|
|
||||||
target_angle += 360
|
|
||||||
# t-
|
|
||||||
# \ \
|
|
||||||
# \ v
|
|
||||||
# \|
|
|
||||||
# s
|
|
||||||
# via_angle is always lower than target_angle, if direction is left.
|
|
||||||
# If they are same, it means they are on a same line of convex hull.
|
|
||||||
if target_angle > via_angle:
|
|
||||||
return Direction.left
|
|
||||||
elif target_angle == via_angle:
|
|
||||||
return Direction.straight
|
|
||||||
else:
|
|
||||||
return Direction.right
|
|
||||||
|
|
||||||
stack: deque[tuple[int, int]] = deque()
|
stack: deque[tuple[int, int]] = deque()
|
||||||
stack.append(sorted_points[0])
|
stack.append(sorted_points[0])
|
||||||
stack.append(sorted_points[1])
|
stack.append(sorted_points[1])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user