Skip to content

Commit c7bed7d

Browse files
jiegilletleios
authored andcommitted
Added Graham Scan in Haskell (#112)
* Added Graham Scan in Haskell * Added forgotten title for C * Added comments
1 parent f10d72d commit c7bed7d

File tree

2 files changed

+37
-5
lines changed

2 files changed

+37
-5
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import Data.List (sortOn, minimumBy)
2+
import Data.Function (on)
3+
4+
type Point = (Double, Double)
5+
6+
ccw :: Point -> Point -> Point -> Double
7+
ccw (xa, ya) (xb, yb) (xc, yc) = (xb - xa) * (yc - ya) - (yb - ya) * (xc - xa)
8+
9+
grahamScan :: [Point] -> [Point]
10+
grahamScan [] = []
11+
grahamScan pts = wrap sortedPts [p0]
12+
where p0@(x, y)= minimumBy (compare `on` snd) pts
13+
sortedPts = sortOn (\(px, py) -> atan2 (py-y) (px-x) ) $ filter (/=p0) pts
14+
wrap [] ps = ps
15+
wrap (s:ss) [p] = wrap ss [s, p]
16+
wrap (s:ss) (p1:p2:ps)
17+
| ccw s p1 p2 > 0 = wrap (s:ss) (p2:ps)
18+
| otherwise = wrap ss (s:p1:p2:ps)
19+
20+
main = do
21+
-- We build the set of points of integer coordinates within a circle of radius 5
22+
let pts = [(x,y) | x<-[-5..5], y<-[-5..5], x^2+y^2<=5^2]
23+
-- And extract the convex hull
24+
print $ grahamScan pts

chapters/computational_geometry/gift_wrapping/graham_scan/graham_scan.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Graham Scan
22

33
At around the same time of the [Jarvis March](jarvis_march.md), R. L. Graham was also developing an algorithm to find the convex hull of a random set of points {{ "gs1972" | cite }}.
4-
Unlike the Jarvis March, which is an $$\mathcal{O}(nh)$$ operation, the Graham Scan is $$\mathcal{O}(n\log(n))$$, where $$n$$ is the number of points and $$h$$ is the size fo the hull.
4+
Unlike the Jarvis March, which is an $$\mathcal{O}(nh)$$ operation, the Graham Scan is $$\mathcal{O}(n\log(n))$$, where $$n$$ is the number of points and $$h$$ is the size fo the hull.
55
This means that the complexity of the Graham Scan is not output-sensitive; moreover, there are some cases where the Jarvis March is more optimal, depending on the size of the hull and the number of points to wrap.
66

7-
Rather than starting at the leftmost point like the Jarvis March, the Graham scan starts at the bottom.
7+
Rather than starting at the leftmost point like the Jarvis March, the Graham scan starts at the bottom.
88
We then sort the distribution of points based on the angle between the bottom-most point, the origin, and each other point.
99
After sorting, we go through point-by-point, searching for points that are on the convex hull and throwing out any other points.
1010
We do this by looking for counter-clockwise rotations.
@@ -14,6 +14,8 @@ We can find whether a rotation is counter-clockwise with trigonometric functions
1414
{% method %}
1515
{% sample lang="jl" %}
1616
[import:6-8, lang:"julia"](code/julia/graham.jl)
17+
{% sample lang="hs" %}
18+
[import:6-7, lang:"haskell"](code/haskell/grahamScan.hs)
1719
{% sample lang="c" %}
1820
[import:24-26, lang:"c_cpp"](code/c/graham.c)
1921
{% endmethod %}
@@ -26,12 +28,14 @@ We basically do not want clockwise rotations, because this means we are at an in
2628
<!---ADD FIGURE--->
2729

2830
To save memory and expensive `append()` operations, we ultimately look for points that should be on the hull and swap them with the first elements in the array.
29-
If there are $$M$$ elements on the hull, then the first $$M$$ elements in our output random distribution of points will be the hull.
31+
If there are $$M$$ elements on the hull, then the first $$M$$ elements in our output random distribution of points will be the hull.
3032
In the end, the code should look something like this:
3133

3234
{% method %}
3335
{% sample lang="jl" %}
3436
[import:10-46, lang:"julia"](code/julia/graham.jl)
37+
{% sample lang="hs" %}
38+
[import:9-18, lang:"haskell"](code/haskell/grahamScan.hs)
3539
{% sample lang="c" %}
3640
[import:65-95, lang:"c_cpp"](code/c/graham.c)
3741
{% endmethod %}
@@ -44,15 +48,20 @@ In the end, the code should look something like this:
4448

4549
{% method %}
4650
{% sample lang="jl" %}
51+
### Julia
4752
[import, lang:"julia"](code/julia/graham.jl)
53+
{% sample lang="hs" %}
54+
### Haskell
55+
[import, lang:"haskell"](code/haskell/grahamScan.hs)
4856
{% sample lang="c" %}
57+
### C
4958
[import, lang:"c_cpp"](code/c/graham.c)
5059
{% endmethod %}
5160

5261
<script>
5362
MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
5463
</script>
55-
$$
64+
$$
5665
\newcommand{\d}{\mathrm{d}}
5766
\newcommand{\bff}{\boldsymbol{f}}
5867
\newcommand{\bfg}{\boldsymbol{g}}
@@ -71,4 +80,3 @@ $$
7180
\newcommand{\bfomega}{\boldsymbol{\omega}}
7281
\newcommand{\bftau}{\boldsymbol{\tau}}
7382
$$
74-

0 commit comments

Comments
 (0)