-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrandomquicksort.hs
111 lines (86 loc) · 2.93 KB
/
randomquicksort.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import System.Random
-- Deterministic quick sort, choosing the first element as the pivot:
qsort :: Ord a => [a] -> [a]
qsort [] = []
qsort (x:xs) = qsort [y | y <- xs, y < x]
++ [x]
++ qsort [y | y <- xs, y >= x]
-- The pivot is the nth element of the list.
getPivot :: [a] -> Int -> (a, [a])
getPivot (x:xs) 0 = (x,xs)
getPivot (x:xs) n = let (p,ys) = getPivot xs (n-1) in (p, x:ys)
-- Now we will choose the pivot randomly, using the Rand monad.
-- A warming-up example:
randomList :: Int -> Rand [Int]
randomList 0 = return []
randomList n = do
i <- randInt
xs <- randomList(n-1)
return(i : xs)
randomList' :: Int -> [Int]
randomList' n = runRand seed (randomList n)
where seed = 3 -- say
-- Randomized quicksort using our random monad.
rqsort :: Ord a => [a] -> Rand [a]
rqsort [] = return []
rqsort xs = do
n <- randIntR (0, length xs - 1)
let (p, ys) = getPivot xs n
as <- rqsort [y | y <- ys, y < p]
bs <- rqsort [y | y <- ys, y >= p]
return(as ++ [p] ++ bs)
rqsort' :: Ord a => [a] -> [a]
rqsort' xs = runRand seed (rqsort xs)
where seed = 3 -- say
-- The monad code. We could instead have imported a library.
data Rand a = Rand(StdGen -> (a , StdGen))
instance Monad Rand where
return x = Rand(\g -> (x,g))
Rand h >>= f = Rand(\g -> let (x, g') = h g
(Rand h') = f x
in h' g')
-- Remove the following to definitions if you have a version of
-- Haskell prior to the monad revolution:
instance Functor Rand where
fmap f xm = xm >>= pure . f
instance Applicative Rand where
pure = return
xm <*> ym = xm >>= \x -> ym >>= pure . x
-- Appendix. Random utilities and more examples:
-- Random Int:
randInt :: Rand Int
randInt = Rand random
-- Random Int in a range:
randIntR :: (Int, Int) -> Rand Int
randIntR (lower, upper) = Rand(randomR(lower, upper))
-- This is how we "can get out" of Rand a:
runRand :: Int -> Rand a -> a
runRand seed (Rand h) = fst(h(mkStdGen seed))
-- Picks a random element with uniform distribution:
uniform :: [a] -> Rand a
uniform xs = do
n <- randIntR (0, length xs - 1)
return(xs !! n)
-- Appendix. Merge sort for comparing efficiency.
msort :: Ord a => [a] -> [a]
msort [] = []
msort [x] = [x]
msort xs = let (ys,zs) = divide xs in merge (msort ys) (msort zs)
divide :: [a] -> ([a],[a])
divide (a:b:xs) = let (ys,zs) = divide xs in (a:ys,b:zs)
divide xs = (xs, [])
divide' :: [a] -> ([a],[a])
divide' xs = let l = length xs
h = l `div` 2
in (take h xs, drop h xs)
-- Clever trick I learned from Tomas Jakl:
divide'' :: [a] -> ([a],[a])
divide'' xs = f xs xs
where f (x:xs) (_:_:ys) = let (as,bs) = f xs ys in (x:as, bs)
f xs _ = ([], xs)
merge :: Ord a => [a] -> [a] -> [a]
merge xs [] = xs
merge [] ys = ys
merge (a:xs) (b:ys)
| a <= b = a : merge xs (b:ys)
| b < a = b : merge (a:xs) ys