Best recursion choice for "penultimax"
Dean Herington
heringto@cs.unc.edu
Mon, 25 Nov 2002 11:04:24 -0500
Mark P Jones wrote:
> Moreover,
> in attempting to "optimize" the code, you might instead break it
> and introduce some bugs that will eventually come back and bite.
Indeed! If we take Mark Phillips's original version of penultimax as our
specification, all four alternate versions are incorrect: They fail to
ignore duplicates of the maximum value. Here are fixed versions.
penultimax2a :: [Int] -> Int
penultimax2a ms = penultimax2' ms 0 0
where
penultimax2' :: [Int] -> Int -> Int -> Int
penultimax2' [] p q = q
penultimax2' (m:ms) p q
| m>p = penultimax2' ms m p
| m==p = penultimax2' ms p q
| m>q = penultimax2' ms p m
| otherwise = penultimax2' ms p q
penultimax3a :: [Int] -> Int
penultimax3a ms = snd (maxpenmax ms)
where
maxpenmax :: [Int] -> (Int,Int)
maxpenmax [] = (0,0)
maxpenmax [m] = (m,0)
maxpenmax (m:ms)
| m>p = (m,p)
| m==p = (p,q)
| m>q = (p,m)
| otherwise = (p,q)
where
(p,q) = maxpenmax ms
penultimax1a :: Ord a => [a] -> a
penultimax1a = head . head . tail . group . sortBy (flip compare)
penultimaxa :: Ord a => [a] -> a
penultimaxa = snd . tournament . map enter
where enter x = (x, [])
tournament [(x, xds)] = (x, maximum xds)
tournament others = tournament (round others)
round ((x,xds):(y,yds):others)
| x>y = (x, y:xds) : rest
| x==y = (x, xds++yds) : rest
| otherwise = (y, x:yds) : rest
where rest = round others
round xs = xs
-- Dean