On distinct opaque keys, a comparison sorting algorithm must distinguish all input orders. Its binary decision tree has at least leaves, because one fixed permutation of the input positions cannot correctly sort two distinct strict orders. A tree of height has at most leaves. Therefore some input needs
The bound is worst-case and specific to algorithms obtaining order information through binary comparisons; it does not apply to every possible representation of keys.
Yes, if a merge takes from its left half when two sort keys compare equal. Within each half the induction hypothesis preserves equal-key order. Across the two halves every left-half occurrence originally preceded every right-half occurrence, and the tie rule preserves that order. Reversing the tie rule would lose stable sorting.
Use merge sort: recursively sort the left and right halves of the array, then merge their ordered outputs using two advancing indices. A merge reads or writes each element a constant number of times, so it costs . There are balanced recursion levels with total work per level. Hence the worst-case running time is ; the standard array implementation uses auxiliary storage.
The displayed procedure calls Find-Set times explicitly, since it tests the two endpoints of every edge. Each successful Union decreases the number of sets by one, from initially to finally, so there are Union calls.
These are calls at the displayed pseudocode level. If a concrete Union(u,v) implementation performs two further internal finds rather than accepting already found roots, its implementation adds find invocations. Counting those separately avoids confusing the procedure's explicit call count with the implementation of a disjoint-set union operation.
Test Find-Set(u) == Find-Set(v). Initially the sets are singleton connected components of the edgeless graph; processing an edge joins precisely the components it connects. By induction over the processed edges, the final sets are exactly the connected components of .
A disjoint-set data structure maintains a partition of a set into pairwise disjoint sets. Make-Set(v) creates the singleton containing a new vertex. Find-Set(v) returns the disjoint-set representative of its current set. Union(u,v) merges the two sets containing its arguments, preserving the partition; it has no effect if they are already the same set. A disjoint-set forest can implement these operations without explicitly moving every member when sets are joined.
With an adjacency list, initialization and the outer loop cost . Each vertex is visited once, and the adjacency scans inspect each edge of a graph twice, once from each endpoint. The total worst-case time is therefore , with labels and recursion-stack space. An adjacency matrix representation instead incurs scanning time.
Start a depth-first search from each as-yet unlabelled vertex, propagating a fresh component number:
component = 0
for u in V:
    cc[u] = UNLABELLED
for u in V:
    if cc[u] == UNLABELLED:
        visit(u, component)
        component = component + 1

visit(u, label):
    cc[u] = label
    for v in adjacency[u]:
        if cc[v] == UNLABELLED:
            visit(v, label)
A search follows only edges, so every vertex it labels is reachable from its root. Conversely, if a reachable vertex remained unlabelled, a path to it would contain a first edge from a visited vertex to an unvisited one; scanning that edge would visit the latter, a contradiction. Thus each search labels exactly one connected component, proving both directions of the required equivalence.
Translate the vertex centroid to the origin, rotate, and translate back:
rotatePoly :: Polygon -> Double -> Polygon
rotatePoly ps theta =
  (translate c . map turn . translate (-cx,-cy)) ps
  where
    c@(cx,cy) = centroid ps
    turn (x,y) = (cos theta*x + sin theta*y,
                 -sin theta*x + cos theta*y)
This follows the supplied rotation matrix, so positive rotates clockwise in the usual Cartesian axes. The opposite signs give the conventional counterclockwise matrix. Since the vertex centroid of the centered vertices is zero and a linear map commutes with their average, the final centroid remains c.
Apply the same translation to every vertex:
translate :: Point -> Polygon -> Polygon
translate (u,v) = map (\(x,y) -> (x+u,y+v))
Every edge vector is unchanged because the added displacement cancels on subtraction. Hence lengths, angles, orientation and shape are preserved.
Here “centroid” means the vertex centroid, the arithmetic mean of the listed vertices, rather than the uniform-area centroid of the polygon's interior:
centroid :: Polygon -> Point
centroid [] = error "centroid: empty vertex list"
centroid ps = (sx/n,sy/n)
  where
    (sx,sy) = foldr (\(x,y) (u,v) -> (x+u,y+v)) (0,0) ps
    n = fromIntegral (length ps)
The nonempty input restriction prevents division by zero; computing both sums and the length takes linear time.
Equal side lengths alone are insufficient: a nonsquare rhombus is not a regular polygon. Use the regular polygon edge rotation criterion: for , successive nonzero edge vectors must be related by the same rotation through either or .
regular :: Polygon -> Bool
regular ps
  | length ps < 3 = False
  | otherwise = norm2 (head es) > 0 && (fits 1 || fits (-1))
  where
    es = [ (u-x,v-y) | ((x,y),(u,v)) <- edges ps ]
    angle = 2*pi / fromIntegral (length ps)
    norm2 (x,y) = x*x+y*y
    close x y = abs (x-y) <= 1e-10 * max 1 (max (abs x) (abs y))
    same (x,y) (u,v) = close x u && close y v
    turn s (x,y) = (cos angle*x - s*sin angle*y,
                    s*sin angle*x + cos angle*y)
    fits s = and (zipWith (\a b -> same (turn s a) b)
                          es (tail es ++ [head es]))
With exact real coordinates and exact equality in same, this is an if-and-only-if test for an ordinary convex regular polygon, in either boundary orientation. The displayed Double implementation tests that condition to the stated tolerance; it cannot promise exact geometric classification near the tolerance boundary. Both orientations are needed, and using the fundamental turn excludes regular star traversals. A repeated zero-length side fails the exact criterion.
First include the closing edge exactly once:
edges :: Polygon -> [(Point,Point)]
edges [] = []
edges ps = zip ps (tail ps ++ [head ps])

perimeter :: Polygon -> Double
perimeter = total . edges
  where total [] = 0
        total ((p,q):es) = distBetween p q + total es

perimeterFold :: Polygon -> Double
perimeterFold = foldr (\(p,q) s -> distBetween p q + s) 0 . edges
The recursive version and right fold both sum the Euclidean distances between consecutive vertices, including the last-to-first pair. They take linear time. The empty-list convention gives zero, although an empty list is not a valid polygon.
The Euclidean distance is
distBetween :: Point -> Point -> Double
distBetween (x,y) (u,v) = sqrt ((x-u)^2 + (y-v)^2)
Thus . The type synonym expands to pairs of floating-point coordinates.
Use
type Point = (Double,Double)
type Polygon = [Point]
A valid polygon is a finite list of at least three vertices in boundary order, with the final vertex connected back to the first. The first vertex is not repeated at the end. A simple polygon also has no intersecting nonadjacent edges. Numerical routines below use finite coordinates; NaN and infinite coordinates are outside this representation's intended domain.
A type synonym is a name for an existing type expression, introduced with type, for example type Name = String. It improves documentation and makes type signatures easier to maintain. It creates no new distinct type: a synonym and its expansion remain interchangeable. An algebraic data type declared with data or newtype has a different role.
Compose the three parsing stages using the supplied fold, and accept only when no suffix remains:
eval :: String -> Maybe Int
eval input = foldMaybe first Nothing (parseInt input)
  where
    first (a,rest) = foldMaybe (second a) Nothing (parseOp rest)
    second a (op,rest) = foldMaybe (finish a op) Nothing (parseInt rest)
    finish a op (b,rest)
      | null rest = Just (apply op a b)
      | otherwise = Nothing
    apply '+' a b = a+b
    apply '-' a b = a-b
    apply '*' a b = a*b
    apply '/' a b = a `div` b
    apply _ _ _ = error "unreachable: parseOp rejected this operator"
Every failed intermediate parser is converted to Nothing by foldMaybe. Checking null rest rejects both a second operation and trailing letters. In particular, integer division makes eval "34/4" = Just 8. As permitted by the question, division by zero is outside the specified inputs; the bounded-Int proviso also applies to arithmetic results.
The parser recognizes exactly one leading operator character:
parseOp :: Parse Char
parseOp (c:cs)
  | c `elem` "+-*/" = Just (c,cs)
parseOp _ = Nothing
An empty input fails, and any later characters remain for the next parser. The last example printed in this part uses the name parseInt; its failure result does not change the requested operator parser.
Separate the maximal decimal prefix from the unconsumed suffix, rejecting an empty prefix:
import Data.Char (isDigit, digitToInt)

type Parse a = String -> Maybe (a,String)

parseInt :: Parse Int
parseInt input =
  case span isDigit input of
    ([],_)  -> Nothing
    (ds,ys) -> Just (foldl (\n d -> 10*n + digitToInt d) 0 ds, ys)
The left fold uses the positional notation recurrence . This parses unsigned decimal operands as illustrated, leaving the first nondigit and everything after it untouched. As the required result type is Int, correct mathematical values require the parsed integer to fit that bounded type; arbitrary-length exact values would instead need Integer or an explicit integer overflow check.

Pinned article: Introduction to the OurBigBook Project

Welcome to the OurBigBook Project! Our goal is to create the perfect publishing platform for STEM subjects, and get university-level students to write the best free STEM tutorials ever.
Everyone is welcome to create an account and play with the site: ourbigbook.com/go/register. We belive that students themselves can write amazing tutorials, but teachers are welcome too. You can write about anything you want, it doesn't have to be STEM or even educational. Silly test content is very welcome and you won't be penalized in any way. Just keep it legal!
We have two killer features:
  1. topics: topics group articles by different users with the same title, e.g. here is the topic for the "Fundamental Theorem of Calculus" ourbigbook.com/go/topic/fundamental-theorem-of-calculus
    Articles of different users are sorted by upvote within each article page. This feature is a bit like:
    • a Wikipedia where each user can have their own version of each article
    • a Q&A website like Stack Overflow, where multiple people can give their views on a given topic, and the best ones are sorted by upvote. Except you don't need to wait for someone to ask first, and any topic goes, no matter how narrow or broad
    This feature makes it possible for readers to find better explanations of any topic created by other writers. And it allows writers to create an explanation in a place that readers might actually find it.
    Figure 1.
    Screenshot of the "Derivative" topic page
    . View it live at: ourbigbook.com/go/topic/derivative
  2. local editing: you can store all your personal knowledge base content locally in a plaintext markup format that can be edited locally and published either:
    This way you can be sure that even if OurBigBook.com were to go down one day (which we have no plans to do as it is quite cheap to host!), your content will still be perfectly readable as a static site.
    Figure 5. . You can also edit articles on the Web editor without installing anything locally.
    Video 3.
    Edit locally and publish demo
    . Source. This shows editing OurBigBook Markup and publishing it using the Visual Studio Code extension.
  3. https://raw.githubusercontent.com/ourbigbook/ourbigbook-media/master/feature/x/hilbert-space-arrow.png
  4. Infinitely deep tables of contents:
    Figure 6.
    Dynamic article tree with infinitely deep table of contents
    .
    Descendant pages can also show up as toplevel e.g.: ourbigbook.com/cirosantilli/chordate-subclade
All our software is open source and hosted at: github.com/ourbigbook/ourbigbook
Further documentation can be found at: docs.ourbigbook.com
Feel free to reach our to us for any help or suggestions: docs.ourbigbook.com/#contact