11package  com .thealgorithms .geometry ;
22
3+ import  java .util .ArrayList ;
34import  java .util .Arrays ;
45import  java .util .Comparator ;
56import  java .util .Stack ;
67
7- /* 
8-  * A Java program that computes the convex hull using the Graham Scan algorithm 
9-  * In the best case, time complexity is O(n), while in the worst case, it is O(nlog(n)). 
10-  * O(n) space complexity 
8+ /** 
9+  * A Java program that computes the convex hull using the Graham Scan algorithm. 
10+  * The time complexity is O(n) in the best case and O(n log(n)) in the worst case. 
11+  * The space complexity is O(n). 
12+  * This algorithm is applicable only to integral coordinates. 
1113 * 
12-  * This algorithm is only applicable to integral coordinates. 
13-  * 
14-  * Reference: 
14+  * References: 
1515 * https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/geometry/graham_scan_algorithm.cpp 
1616 * https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/geometry/graham_scan_functions.hpp 
1717 * https://algs4.cs.princeton.edu/99hull/GrahamScan.java.html 
1818 */ 
1919public  class  GrahamScan  {
20+ 
2021    private  final  Stack <Point > hull  = new  Stack <>();
2122
2223    public  GrahamScan (Point [] points ) {
23- 
24-         /* 
25-          * pre-process the points by sorting them with respect to the bottom-most point, then we'll 
26-          * push the first point in the array to be our first extreme point. 
27-          */ 
24+         // Pre-process points: sort by y-coordinate, then by polar order with respect to the first point 
2825        Arrays .sort (points );
2926        Arrays .sort (points , 1 , points .length , points [0 ].polarOrder ());
27+ 
3028        hull .push (points [0 ]);
3129
32-         // find index of  first point not equal to a [0] (indexPoint1) and the first point that's not  
33-         // collinear with either (indexPoint2).  
34-         int  indexPoint1 ;
35-         for  (indexPoint1  = 1 ; indexPoint1  < points .length ; indexPoint1 ++) {
36-             if  (!points [0 ].equals (points [indexPoint1 ])) {
30+         // Find the  first point not equal to points [0] (firstNonEqualIndex)  
31+         // and the first point not  collinear firstNonCollinearIndex  with the previous points  
32+         int  firstNonEqualIndex ;
33+         for  (firstNonEqualIndex  = 1 ; firstNonEqualIndex  < points .length ; firstNonEqualIndex ++) {
34+             if  (!points [0 ].equals (points [firstNonEqualIndex ])) {
3735                break ;
3836            }
3937        }
40-         if  (indexPoint1  == points .length ) {
38+ 
39+         if  (firstNonEqualIndex  == points .length ) {
4140            return ;
4241        }
4342
44-         int  indexPoint2 ;
45-         for  (indexPoint2  = indexPoint1  + 1 ; indexPoint2  < points .length ; indexPoint2 ++) {
46-             if  (Point .orientation (points [0 ], points [indexPoint1 ], points [indexPoint2 ]) != 0 ) {
43+         int  firstNonCollinearIndex ;
44+         for  (firstNonCollinearIndex  = firstNonEqualIndex  + 1 ; firstNonCollinearIndex  < points .length ; firstNonCollinearIndex ++) {
45+             if  (Point .orientation (points [0 ], points [firstNonEqualIndex ], points [firstNonCollinearIndex ]) != 0 ) {
4746                break ;
4847            }
4948        }
50-         hull .push (points [indexPoint2  - 1 ]);
5149
52-         // Now we simply add the point to the stack based on the orientation. 
53-         for  (int  i  = indexPoint2 ; i  < points .length ; i ++) {
50+         hull .push (points [firstNonCollinearIndex  - 1 ]);
51+ 
52+         // Process the remaining points and update the hull 
53+         for  (int  i  = firstNonCollinearIndex ; i  < points .length ; i ++) {
5454            Point  top  = hull .pop ();
5555            while  (Point .orientation (hull .peek (), top , points [i ]) <= 0 ) {
5656                top  = hull .pop ();
@@ -61,14 +61,10 @@ public GrahamScan(Point[] points) {
6161    }
6262
6363    /** 
64-      * @return A stack  of points representing the convex hull. 
64+      * @return An iterable collection  of points representing the convex hull. 
6565     */ 
6666    public  Iterable <Point > hull () {
67-         Stack <Point > s  = new  Stack <>();
68-         for  (Point  p  : hull ) {
69-             s .push (p );
70-         }
71-         return  s ;
67+         return  new  ArrayList <>(hull );
7268    }
7369
7470    public  record  Point (int  x , int  y ) implements  Comparable <Point > {
@@ -98,80 +94,65 @@ public int y() {
9894        }
9995
10096        /** 
101-          * Finds  the orientation of ordered  triplet. 
97+          * Determines  the orientation of the  triplet (a, b, c) . 
10298         * 
103-          * @param a Co-ordinates of point a <int, int> 
104-          * @param b Co-ordinates of point a <int, int> 
105-          * @param c Co-ordinates of point a <int, int> 
106-          * @return { -1, 0, +1 } if a -→ b -→ c is a { clockwise, collinear; counterclockwise } 
107-          *     turn. 
99+          * @param a The first point 
100+          * @param b The second point 
101+          * @param c The third point 
102+          * @return -1 if (a, b, c) is clockwise, 0 if collinear, +1 if counterclockwise 
108103         */ 
109104        public  static  int  orientation (Point  a , Point  b , Point  c ) {
110105            int  val  = (b .x  - a .x ) * (c .y  - a .y ) - (b .y  - a .y ) * (c .x  - a .x );
111-             if  (val  == 0 ) {
112-                 return  0 ;
113-             }
114-             return  (val  > 0 ) ? +1  : -1 ;
106+             return  Integer .compare (val , 0 );
115107        }
116108
117109        /** 
118-          * @param p2 Co-ordinate of  point to compare to . 
119-          * This function will compare the points and will return a positive integer if the  
120-          * point is greater than the argument  point and a negative integer if the point is  
121-          * less than the argument  point.  
110+          * Compares this  point with another point . 
111+          * 
112+          * @param p2 The  point to compare to  
113+          * @return A positive integer if this  point is greater, a negative integer if less, or 0 if equal  
122114         */ 
115+         @ Override 
123116        public  int  compareTo (Point  p2 ) {
124-             int  res  = Integer .compare (this .y , p2 .y );
125-             if  (res  == 0 ) {
126-                 res  = Integer .compare (this .x , p2 .x );
127-             }
128-             return  res ;
117+             int  cmpY  = Integer .compare (this .y , p2 .y );
118+             return  cmpY  != 0  ? cmpY  : Integer .compare (this .x , p2 .x );
129119        }
130120
131121        /** 
132-          * A helper function that will let us sort points by their polar order 
133-          * This function will compare the angle between 2 polar Co-ordinates 
122+          * Returns a comparator to sort points by their polar order relative to this point. 
134123         * 
135-          * @return the  comparator 
124+          * @return A polar order  comparator 
136125         */ 
137126        public  Comparator <Point > polarOrder () {
138127            return  new  PolarOrder ();
139128        }
140129
141130        private  final  class  PolarOrder  implements  Comparator <Point > {
131+             @ Override 
142132            public  int  compare (Point  p1 , Point  p2 ) {
143133                int  dx1  = p1 .x  - x ;
144134                int  dy1  = p1 .y  - y ;
145135                int  dx2  = p2 .x  - x ;
146136                int  dy2  = p2 .y  - y ;
147137
148138                if  (dy1  >= 0  && dy2  < 0 ) {
149-                     return  -1 ; // q1  above; q2 below  
139+                     return  -1 ; // p1  above p2  
150140                } else  if  (dy2  >= 0  && dy1  < 0 ) {
151-                     return  +1 ; // q1 below; q2 above 
152-                 } else  if  (dy1  == 0  && dy2  == 0 ) { // 3-collinear and horizontal 
153-                     if  (dx1  >= 0  && dx2  < 0 ) {
154-                         return  -1 ;
155-                     } else  if  (dx2  >= 0  && dx1  < 0 ) {
156-                         return  +1 ;
157-                     } else  {
158-                         return  0 ;
159-                     }
141+                     return  1 ; // p1 below p2 
142+                 } else  if  (dy1  == 0  && dy2  == 0 ) { // Collinear and horizontal 
143+                     return  Integer .compare (dx2 , dx1 );
160144                } else  {
161-                     return  -orientation (Point .this , p1 , p2 ); // both above or below  
145+                     return  -orientation (Point .this , p1 , p2 ); // Compare orientation  
162146                }
163147            }
164148        }
165149
166150        /** 
167-          * Override of the toString method, necessary to compute the difference 
168-          * between the expected result and the derived result 
169-          * 
170-          * @return a string representation of any given 2D point in the format (x, y) 
151+          * @return A string representation of this point in the format (x, y) 
171152         */ 
172153        @ Override 
173154        public  String  toString () {
174-             return  "("  +  x  +  ", "  +  y  +  ")" ;
155+             return  String . format ( "(%d, %d)" ,  x ,  y ) ;
175156        }
176157    }
177158}
0 commit comments