Movatterモバイル変換


[0]ホーム

URL:


Data Structures & Algorithms Tutorial

DSA - Geometric Algorithms



Geometric algorithms are defined as a procedure used for solving problems related to geometric shapes and their properties. These algorithms can be applied to shapes like points, lines, polygons, and other geometric figures. We can find its applications in various fields such as computer graphics, computer-aided design, robotics, and geographical information systems.

Problems related to Geometric Algorithms

Some of the common problems that can be solved using geometric algorithms are −

  • It can be used to solve area of different polygons, such as triangle, rectangle and so on.

  • We can use geometric algorithm to find intersection of two lines.

  • Computing convex hull problem.

  • Finding a point inside different geometric shapes.

  • Geometric algorithms can solve triangulation of polygon problem.

Important Geometric Algorithms

Some of the important geometric algorithms are −

  • Graham Scan Algorithm

  • Sweep Line Algorithm

Graham Scan Algorithm

TheGraham Scan Algorithm was developed by Ronald Graham in 1972. This algorithm is primarily used to solve Convex Hull problem and Maximum distance problem. Its application can be seen in other fields also, such as image processing, robotics, delivery systems and many more.

The following steps explain the working Graham Scan algorithm −

  • First, find the point with the lowest y-coordinate. If multiple points share the lowest y-coordinate, choose the one with the lowest x-coordinate.

  • Sort the remaining points based on their polar angle with respect to the lowest point.

  • After sorting the points, start with the lowest point and other two additional points. These three points form the initial part of the convex hull.

  • For each new point, determine whether travelling from the two preceding points constitutes a left turn or a right turn. If it's a right turn, the second-to-last point is not inside the convex hull.

  • Repeat this process until a left turn set is encountered.

Example

The following example practically demonstrates how Graham Scan algorithm works.

#include <stdio.h>#include <stdlib.h>// Structure for a pointstruct Point2D {    int x, y;};// Global variable for the initial pointstruct Point2D initialPoint;// Function to get the second top elementstruct Point2D getSecondTop(struct Point2D Stack[], int* top) {    return Stack[(*top)-1];}// Function to calculate square of distance between two pointsint calcDistSq(struct Point2D p1, struct Point2D p2) {    return (p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y);}// Function to find orientation of ordered triplet of pointsint getOrientation(struct Point2D p, struct Point2D q, struct Point2D r) {    int 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;}// Function to compare two pointsint comparePoints(const void *vp1, const void *vp2) {    struct Point2D *p1 = (struct Point2D *)vp1;    struct Point2D *p2 = (struct Point2D *)vp2;    int o = getOrientation(initialPoint, *p1, *p2);    if (o == 0)        return (calcDistSq(initialPoint, *p2) >= calcDistSq(initialPoint, *p1))? -1 : 1;    return (o == 2)? -1: 1;}// Function to compute the convex hullvoid computeConvexHull(struct Point2D points[], int n) {    int ymin = points[0].y, min = 0;    for (int i = 1; i < n; i++) {        int y = points[i].y;        if ((y < ymin) || (ymin == y && points[i].x < points[min].x))            ymin = points[i].y, min = i;    }    // Swapping    struct Point2D temp = points[0];    points[0] = points[min];    points[min] = temp;    // Initial point    initialPoint = points[0];    // Sort array of points    qsort(&points[1], n-1, sizeof(struct Point2D), comparePoints);    int m = 1;    for (int i=1; i<n; i++) {        while (i < n-1 && getOrientation(initialPoint, points[i], points[i+1]) == 0)            i++;        points[m] = points[i];        m++;    }    if (m < 3) return;    // Stack to store the points on the convex hull    struct Point2D Stack[n];    int top = -1;    // Push the first three points into the stack    Stack[++top] = points[0];    Stack[++top] = points[1];    Stack[++top] = points[2];    // For the rest of the points    for (int i = 3; i < m; i++) {        while (getOrientation(getSecondTop(Stack, &top), Stack[top], points[i]) != 2)            top--;        Stack[++top] = points[i];    }    // Print the point    while (top != -1) {        struct Point2D p = Stack[top--];        printf("(%d, %d)\n", p.x, p.y);    }}int main() {    struct Point2D points[] = {{0, 1}, {1, 2}, {2, 3}, {4, 5}, {0, 0}, {2, 1}, {3, 1}, {3, 3}};    int n = sizeof(points)/ sizeof(points[0]);    computeConvexHull(points, n);    return 0;}
#include <iostream>#include <vector>#include <algorithm>using namespace std;// structure for a point struct Point2D {    int x, y;};// initial pointPoint2D initialPoint;// Function to get the next top element Point2D getSecondTop(vector<Point2D> &Stack) {    return Stack[Stack.size()-2]; }// Function to calculate square of distance between two pointsint calcDistSq(Point2D p1, Point2D p2) {    return (p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y);}// Function to find orientation of ordered triplet of pointsint getOrientation(Point2D p, Point2D q, Point2D r) {    int val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);    if (val == 0) return 0;     // checking clock or counterclock wise    return (val > 0)? 1: 2; }// Function to compare two pointsint comparePoints(const void *vp1, const void *vp2) {    Point2D *p1 = (Point2D *)vp1;    Point2D *p2 = (Point2D *)vp2;    int o = getOrientation(initialPoint, *p1, *p2);    if (o == 0)        return (calcDistSq(initialPoint, *p2) >= calcDistSq(initialPoint, *p1))? -1 : 1;    return (o == 2)? -1: 1;}// Function to compute the convex hull void computeConvexHull(Point2D points[], int n) {    int ymin = points[0].y, min = 0;    for (int i = 1; i < n; i++) {        int y = points[i].y;        if ((y < ymin) || (ymin == y && points[i].x < points[min].x))            ymin = points[i].y, min = i;    }    // swapping    swap(points[0], points[min]);     // initial point    initialPoint = points[0];     // Sort array of points    qsort(&points[1], n-1, sizeof(Point2D), comparePoints);     int m = 1;     for (int i=1; i<n; i++) {        while (i < n-1 && getOrientation(initialPoint, points[i], points[i+1]) == 0)            i++;         points[m] = points[i];         m++;     }    if (m < 3) return;     // stack to store the points on the convex hull    vector<Point2D> Stack;     // Push the first three points into the stack    Stack.push_back(points[0]);     Stack.push_back(points[1]);    Stack.push_back(points[2]);    // For the rest of the points    for (int i = 3; i < m; i++) {         while (getOrientation(getSecondTop(Stack), Stack.back(), points[i]) != 2)            Stack.pop_back();         Stack.push_back(points[i]);     }    // Print the point    while (!Stack.empty()) {         Point2D p = Stack.back();         cout << "(" << p.x << ", " << p.y <<")" << endl;         Stack.pop_back();     }}int main() {    Point2D points[] = {{0, 1}, {1, 2}, {2, 3}, {4, 5}, {0, 0}, {2, 1}, {3, 1}, {3, 3}};    int n = sizeof(points)/ sizeof(points[0]);     computeConvexHull(points, n);     return 0;}
import java.util.*;// class to represent points with x and y coordinatesclass Cords {    int xCoord, yCoord;    // Constructor     Cords(int x, int y) {        this.xCoord = x;        this.yCoord = y;    }}// class to find the convex hull public class ConvexHullFinder {    // initial point    Cords initialPoint;    // Method to get the next to top element    Cords getSecondTop(Stack<Cords> stack) {        Cords temp = stack.pop();        Cords result = stack.peek();        stack.push(temp);        return result;    }    // Method to swap two points    void swapPoints(Cords p1, Cords p2) {        Cords temp = p1;        p1 = p2;        p2 = temp;    }    // Method to calculate the square of the distance between two points    int distanceSquare(Cords p1, Cords p2) {        return (p1.xCoord - p2.xCoord)*(p1.xCoord - p2.xCoord) + (p1.yCoord - p2.yCoord)*(p1.yCoord - p2.yCoord);    }    // Method to find the orientation of an ordered triplet of points    int findOrientation(Cords p, Cords q, Cords r) {        int value = (q.yCoord - p.yCoord) * (r.xCoord - q.xCoord) - (q.xCoord - p.xCoord) * (r.yCoord - q.yCoord);        if (value == 0) return 0;         // checking clock or counterclock wise        return (value > 0)? 1: 2;     }    // Method to check if two points have same slope     boolean sameSlope(Cords p1, Cords p2, Cords p3) {        return (p2.yCoord - p1.yCoord) * (p3.xCoord - p2.xCoord) == (p3.yCoord - p2.yCoord) * (p2.xCoord - p1.xCoord);    }    // method to calculate convex hull     void calculateConvexHull(Cords points[], int n) {        int yMin = points[0].yCoord, min = 0;        for (int i = 1; i < n; i++) {            int y = points[i].yCoord;            if ((y < yMin) || (yMin == y && points[i].xCoord < points[min].xCoord)) {                yMin = points[i].yCoord;                min = i;            }        }        // Swapping        swapPoints(points[0], points[min]);        // initial point        initialPoint = points[0];        // Sort array of points        Arrays.sort(points, new Comparator<Cords>() {            @Override            public int compare(Cords p1, Cords p2) {                if (sameSlope(initialPoint, p1, p2)) {                    if (distanceSquare(initialPoint, p2) >= distanceSquare(initialPoint, p1)) {                        return -1;                    } else {                        return 1;                    }                }                if (findOrientation(initialPoint, p1, p2) == 2) {                    return -1;                } else {                    return 1;                }            }        });        // Create a stack and push the first three points into it        Stack<Cords> stack = new Stack<>();        stack.push(points[0]);        stack.push(points[1]);        stack.push(points[2]);        // keep removing top of stack while we get a clockwise turn        for (int i = 3; i < n; i++) {            while (stack.size() > 1 && findOrientation(getSecondTop(stack), stack.peek(), points[i]) != 2)                stack.pop();            stack.push(points[i]);        }        // print result        while (!stack.empty()) {            Cords p = stack.peek();            System.out.println("(" + p.xCoord + ", " + p.yCoord + ")");            stack.pop();        }    }    public static void main(String[] args) {        // points        Cords points[] = {new Cords(0, 1), new Cords(1, 2), new Cords(2, 3), new Cords(4, 5),                new Cords(0, 0), new Cords(2, 1), new Cords(3, 1), new Cords(3, 3)};        int n = points.length;        ConvexHullFinder finder = new ConvexHullFinder();        finder.calculateConvexHull(points, n);    }}
from functools import cmp_to_keyimport math# Class to represent points with x and y coordinatesclass Cords:    def __init__(self, x, y):        self.xCoord = x        self.yCoord = y# Class to find the convex hullclass ConvexHullFinder:    # Initial point    initialPoint = None    # Method to get the next to top element    def getSecondTop(self, stack):        return stack[-2]    # Method to swap two points    def swapPoints(self, p1, p2):        return p2, p1    # Method to calculate the square of the distance between two points    def distanceSquare(self, p1, p2):        return (p1.xCoord - p2.xCoord)**2 + (p1.yCoord - p2.yCoord)**2    # Method to find the orientation of an ordered triplet of points    def findOrientation(self, p, q, r):        value = (q.yCoord - p.yCoord) * (r.xCoord - q.xCoord) - (q.xCoord - p.xCoord) * (r.yCoord - q.yCoord)        if value == 0: return 0        return 1 if value > 0 else 2    # Method to check if two points have same slope    def sameSlope(self, p1, p2, p3):        return (p2.yCoord - p1.yCoord) * (p3.xCoord - p2.xCoord) == (p3.yCoord - p2.yCoord) * (p2.xCoord - p1.xCoord)    # Method to calculate convex hull    def calculateConvexHull(self, points):        n = len(points)        ymin = points[0].yCoord        min = 0        for i in range(1, n):            y = points[i].yCoord            if (y < ymin) or (ymin == y and points[i].xCoord < points[min].xCoord):                ymin = points[i].yCoord                min = i        # Swapping        points[0], points[min] = self.swapPoints(points[0], points[min])        # Initial point        self.initialPoint = points[0]        # Sort array of points        def compare(p1, p2):            if self.sameSlope(self.initialPoint, p1, p2):                if self.distanceSquare(self.initialPoint, p2) >= self.distanceSquare(self.initialPoint, p1):                    return -1                else:                    return 1            if self.findOrientation(self.initialPoint, p1, p2) == 2:                return -1            else:                return 1        points = sorted(points, key=cmp_to_key(compare))        # Create a stack and push the first three points into it        stack = []        stack.append(points[0])        stack.append(points[1])        stack.append(points[2])        # Keep removing top of stack while we get a clockwise turn        for i in range(3, n):            while len(stack) > 1 and self.findOrientation(self.getSecondTop(stack), stack[-1], points[i]) != 2:                stack.pop()            stack.append(points[i])        # Print result        while stack:            p = stack[-1]            print("(", p.xCoord, ", ", p.yCoord, ")")            stack.pop()# Pointspoints = [Cords(0, 1), Cords(1, 2), Cords(2, 3), Cords(4, 5),          Cords(0, 0), Cords(2, 1), Cords(3, 1), Cords(3, 3)]finder = ConvexHullFinder()finder.calculateConvexHull(points)

Output

(0, 1)(4, 5)(3, 1)(0, 0)

Sweep Line Algorithm

TheSweep Line Algorithm is used to solve geometric and other problems involving dynamic sets of objects moving in a specific direction. Suppose a vertical line (say it sweep line) moving from left to right across the plane. As the sweep line encounters endpoints of line segments, we track which segments intersect at each point in time. By analyzing the interactions, we can efficiently solve various problems.

Following are the steps involved in Sweep Line Algorithm −

  • The sweep line starts at one end of the problem space and moves towards the other.

  • At regular intervals, the algorithm update a suitable data structure depending on the problem. Based on the current configuration of the sweep line position, it calculates distances, intersections, areas, or other desired outputs.

  • The final data structures or accumulated results provide the solution to the problem.

Example

Following is the example illustrating sweep line algorithm in various programming language.

#include <stdio.h>#include <math.h>// Structure to represent a coordinatetypedef struct {   double a, b;} Coordinate;// Structure to represent a line segmenttypedef struct {   Coordinate start, end;} Segment;// Function to check if two line segments intersectint checkIntersection(Segment s1, Segment s2) {   //    return 0; }// Function to find the intersection point of two line segmentsCoordinate findIntersection(Segment s1, Segment s2) {   // coordinates of the start and end points of the first line segment   double a1 = s1.start.a, b1 = s1.start.b;   double a2 = s1.end.a, b2 = s1.end.b;   // coordinates of the start and end points of the second line segment   double a3 = s2.start.a, b3 = s2.start.b;   double a4 = s2.end.a, b4 = s2.end.b;   // Calculate the denominator of the intersection formula   double denominator = (b4 - b3) * (a2 - a1) - (a4 - a3) * (b2 - b1);   double numerator1 = (a4 - a3) * (b1 - b3) - (b4 - b3) * (a1 - a3);   double numerator2 = (a2 - a1) * (b1 - b3) - (b2 - b1) * (a1 - a3);   // If the denominator is zero, the lines are parallel   if (denominator == 0) {      return (Coordinate){ INFINITY, INFINITY };   }   double u = numerator1 / denominator;   double v = numerator2 / denominator;   if (u >= 0 && u <= 1 && v >= 0 && v <= 1) {      double a = a1 + u * (a2 - a1);      double b = b1 + u * (b2 - b1);      return (Coordinate){ a, b };   }   return (Coordinate){ INFINITY, INFINITY };}int main() {   // line segments   Segment s1 = { { 1, 2 }, { 3, 2 } };   Segment s2 = { { 2, 1 }, { 2, 3 } };   // If the line segments intersect   if (checkIntersection(s1, s2)) {      // Find the intersection point      Coordinate c = findIntersection(s1, s2);      printf("Intersection point: (%f, %f)\n", c.a, c.b);   } else {      printf("Segments do not intersect\n");   }   return 0;}
#include <bits/stdc++.h>#include <iostream>using namespace std;// structure to represent a coordinatestruct Coordinate {   double a, b;};// structure to represent a line segmentstruct Segment {   Coordinate start, end;};// Function to check if two line segments intersectbool checkIntersection(Segment s1, Segment s2){    //}// Function to find the intersection point of two line segmentsCoordinate findIntersection(Segment s1, Segment s2) {   // coordinates of the start and end points of the first line segment   double a1 = s1.start.a, b1 = s1.start.b;   double a2 = s1.end.a, b2 = s1.end.b;   // coordinates of the start and end points of the second line segment   double a3 = s2.start.a, b3 = s2.start.b;   double a4 = s2.end.a, b4 = s2.end.b;   // Calculate the denominator of the intersection formula   double denominator = (b4 - b3) * (a2 - a1) - (a4 - a3) * (b2 - b1);   // Calculate the numerators of the intersection formula   double numerator1 = (a4 - a3) * (b1 - b3) - (b4 - b3) * (a1 - a3);   double numerator2 = (a2 - a1) * (b1 - b3) - (b2 - b1) * (a1 - a3);   // If the denominator is zero, the lines are parallel   if (denominator == 0) {      return { INFINITY, INFINITY };   }   double u = numerator1 / denominator;   double v = numerator2 / denominator;   // If u and v are both between 0 and 1, the line segments intersect   if (u >= 0 && u <= 1 && v >= 0 && v <= 1) {      // Calculate the coordinates of the intersection point      double a = a1 + u * (a2 - a1);      double b = b1 + u * (b2 - b1);      return { a, b };   }   // If u or v is not between 0 and 1, the line segments do not intersect   return { INFINITY, INFINITY };}int main(){   // line segments   Segment s1 = { { 1, 2 }, { 3, 2 } };   Segment s2 = { { 2, 1 }, { 2, 3 } };   // If the line segments intersect   if (checkIntersection(s1, s2)) {      // Find the intersection point      Coordinate c = findIntersection(s1, s2);      // Print the intersection point      cout << "Intersection point: (" << c.a << ", " << c.b << ")" << endl;   } else {      cout << "Segments do not intersect" << endl;   }   return 0;}
public class Main {   // Class to represent a coordinate   static class Coordinate {      double a, b;      Coordinate(double a, double b) {         this.a = a;         this.b = b;      }   }   // Class to represent a line segment   static class Segment {      Coordinate start, end;      Segment(Coordinate start, Coordinate end) {         this.start = start;         this.end = end;      }   }   // Method to check if two line segments intersect   static boolean checkIntersection(Segment s1, Segment s2) {      return false;    }   // Method to find the intersection point of two line segments   static Coordinate findIntersection(Segment s1, Segment s2) {      double a1 = s1.start.a, b1 = s1.start.b;      double a2 = s1.end.a, b2 = s1.end.b;      double a3 = s2.start.a, b3 = s2.start.b;      double a4 = s2.end.a, b4 = s2.end.b;      double denominator = (b4 - b3) * (a2 - a1) - (a4 - a3) * (b2 - b1);      double numerator1 = (a4 - a3) * (b1 - b3) - (b4 - b3) * (a1 - a3);      double numerator2 = (a2 - a1) * (b1 - b3) - (b2 - b1) * (a1 - a3);      if (denominator == 0) {         return new Coordinate(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);      }      double u = numerator1 / denominator;      double v = numerator2 / denominator;      if (u >= 0 && u <= 1 && v >= 0 && v <= 1) {         double a = a1 + u * (a2 - a1);         double b = b1 + u * (b2 - b1);         return new Coordinate(a, b);      }      return new Coordinate(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);   }   public static void main(String[] args) {      Segment s1 = new Segment(new Coordinate(1, 2), new Coordinate(3, 2));      Segment s2 = new Segment(new Coordinate(2, 1), new Coordinate(2, 3));      if (checkIntersection(s1, s2)) {         Coordinate c = findIntersection(s1, s2);         System.out.println("Intersection point: (" + c.a + ", " + c.b + ")");      } else {         System.out.println("Segments do not intersect");      }   }}
import math# Class to represent a coordinateclass Coordinate:    def __init__(self, a, b):        self.a = a        self.b = b# Class to represent a line segmentclass Segment:    def __init__(self, start, end):        self.start = start        self.end = end# Function to check if two line segments intersectdef checkIntersection(s1, s2):    # Implement intersection checking algorithm here    return False  # Placeholder return statement# Function to find the intersection point of two line segmentsdef findIntersection(s1, s2):    a1, b1 = s1.start.a, s1.start.b    a2, b2 = s1.end.a, s1.end.b    a3, b3 = s2.start.a, s2.start.b    a4, b4 = s2.end.a, s2.end.b    denominator = (b4 - b3) * (a2 - a1) - (a4 - a3) * (b2 - b1)    numerator1 = (a4 - a3) * (b1 - b3) - (b4 - b3) * (a1 - a3)    numerator2 = (a2 - a1) * (b1 - b3) - (b2 - b1) * (a1 - a3)    if denominator == 0:        return Coordinate(math.inf, math.inf)    u = numerator1 / denominator    v = numerator2 / denominator    if 0 <= u <= 1 and 0 <= v <= 1:        a = a1 + u * (a2 - a1)        b = b1 + u * (b2 - b1)        return Coordinate(a, b)    return Coordinate(math.inf, math.inf)# Test the functionss1 = Segment(Coordinate(1, 2), Coordinate(3, 2))s2 = Segment(Coordinate(2, 1), Coordinate(2, 3))if checkIntersection(s1, s2):    c = findIntersection(s1, s2)    print(f"Intersection point: ({c.a}, {c.b})")else:    print("Segments do not intersect")

Output

Segments do not intersect
Print Page
Advertisements

[8]ページ先頭

©2009-2025 Movatter.jp