``quicksort [] = [] quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater) where lesser = filter (< p) xs greater = filter (>= p) xs` `

` `// To sort array a[] of size n: qsort(a,0,n-1) void qsort(int a[], int lo, int hi) { int h, l, p, t; if (lo < hi) { l = lo; h = hi; p = a[hi]; do { while ((l < h) && (a[l] <= p)) l = l+1; while ((h > l) && (a[h] >= p)) h = h-1; if (l < h) { t = a[l]; a[l] = a[h]; a[h] = t; } } while (l < h); a[hi] = a[l]; a[l] = p; qsort( a, lo, l-1 ); qsort( a, l+1, hi ); } }` `

C版本下面的链接指向一个页面，该页面声明“引言中引用的快速sorting不是”真正的“快速sorting，并且不像c代码那样对较长的列表进行缩放。

1. 分而治之; 把问题分解成两个小问题。
2. 分隔元素。

` `import qualified Data.Vector.Generic as V import qualified Data.Vector.Generic.Mutable as M qsort :: (V.Vector va, Ord a) => va -> va qsort = V.modify go where go xs | M.length xs < 2 = return () | otherwise = do p <- M.read xs (M.length xs `div` 2) j <- M.unstablePartition (< p) xs let (l, pr) = M.splitAt j xs k <- M.unstablePartition (== p) pr go l; go \$ M.drop k pr` `

` `import Control.Monad import Data.Array.IO import Data.IORef qsort :: IOUArray Int Int -> Int -> Int -> IO () qsort a lo hi = do (h,l,p,t) <- liftM4 (,,,) zzzz when (lo < hi) \$ do l .= lo h .= hi p .=. (a!hi) doWhile (get l .< get h) \$ do while ((get l .< get h) .&& ((a.!l) .<= get p)) \$ do modifyIORef l succ while ((get h .> get l) .&& ((a.!h) .>= get p)) \$ do modifyIORef h pred b <- get l .< get h when b \$ do t .=. (a.!l) lVal <- get l hVal <- get h writeArray a lVal =<< a!hVal writeArray a hVal =<< get t lVal <- get l writeArray a hi =<< a!lVal writeArray a lVal =<< get p hi' <- fmap pred (get l) qsort a lo hi' lo' <- fmap succ (get l) qsort a lo' hi` `

` ` let z :: IO (IORef Int) z = newIORef 0 (.=) = writeIORef ref .=. action = do v <- action; ref .= v (!) = readArray (.!) a ref = readArray a =<< get ref get = readIORef (.<) = liftM2 (<) (.>) = liftM2 (>) (.<=) = liftM2 (<=) (.>=) = liftM2 (>=) (.&&) = liftM2 (&&) -- ... where doWhile cond foo = do foo b <- cond when b \$ doWhile cond foo while cond foo = do b <- cond when b \$ foo >> while cond foo` `

` `main = do a <- (newListArray (0,9) [10,9..1]) :: IO (IOUArray Int Int) printArr a putStrLn "Sorting..." qsort a 0 9 putStrLn "Sorted." printArr a where printArr a = mapM_ (\x -> print =<< readArray ax) [0..9]` `

` `main = putStrLn (show (quicksort [8, 6, 7, 5, 3, 0, 9]))` `

GHC的`putStrLn`实现通过将参数String的字符复制到输出缓冲区来工作。 但是当它进入这个循环时， `show`还没有运行。 因此，当它从string中复制第一个字符时，Haskell将计算`show`和计算该字符所需的`quicksort`的部分。 然后`putStrLn`移动到下一个字符。 因此，所有三个函数（ `putStrLn``show``putStrLn`的执行都是交错的。 `quicksort`以递增方式执行，留下未经评估的thunk的graphics，以便记住它停留的位置。

PS如果Haskell的代码和quicksort做了相同数量的比较，那么Haskell代码会更快一些。 所写的代码执行两倍的比较，因为`lesser``greater`的指定是独立计算的，通过列表进行两次线性扫描。 当然，编译器原则上可以足够聪明以消除额外的比较; 或者代码可以改为使用`Data.List.partition`

1. 通过累加器优化连接（++），这是一个线性操作：

` `qsort xs = qsort' xs [] qsort' [] r = r qsort' [x] r = x:r qsort' (x:xs) r = qpart xs [] [] r where qpart [] as bs r = qsort' as (x:qsort' bs r) qpart (x':xs') as bs r | x' <= x = qpart xs' (x':as) bs r | x' > x = qpart xs' as (x':bs) r` `
2. 优化到三元快速sorting（由Bentley和Sedgewick提到的3路分区），以处理重复的元素：

` `tsort :: (Ord a) => [a] -> [a] tsort [] = [] tsort (x:xs) = tsort [a | a<-xs, a<x] ++ x:[b | b<-xs, b==x] ++ tsort [c | c<-xs, c>x]` `
3. 结合2和3，参考Richard Bird的书：

` `psort xs = concat \$ pass xs [] pass [] xss = xss pass (x:xs) xss = step xs [] [x] [] xss where step [] as bs cs xss = pass as (bs:pass cs xss) step (x':xs') as bs cs xss | x' < x = step xs' (x':as) bs cs xss | x' == x = step xs' as (x':bs) cs xss | x' > x = step xs' as bs (x':cs) xss` `

` ` tqsort xs = tqsort' xs [] tqsort' [] r = r tqsort' (x:xs) r = qpart xs [] [x] [] r where qpart [] as bs cs r = tqsort' as (bs ++ tqsort' cs r) qpart (x':xs') as bs cs r | x' < x = qpart xs' (x':as) bs cs r | x' == x = qpart xs' as (x':bs) cs r | x' > x = qpart xs' as bs (x':cs) r` `

` ` qsort [] = [] qsort [x] = [x] qsort [x, y] = [min xy, max xy] qsort (x:y:z:rest) = qsort (filter (< m) (s:rest)) ++ [m] ++ qsort (filter (>= m) (l:rest)) where xs = [x, y, z] [s, m, l] = [minimum xs, median xs, maximum xs]` `

1. [1，2，3，4，…，n]

2. [n，n-1，n-2，…，1]

3. [m-1，m-2，… 3,2,1，m + 1，m + 2，…，n]

4. [n，1，n-1,2，…]

Pro：它通过稳定性改进了“真正的”快速sorting，即它保留了相同元素之间的序列次序。

Pro：推广到三向分裂（<=>）是微不足道的，它避免了由于某个值出现O（n）次而导致的二次行为。

Pro：即使必须包含filter的定义，也更容易阅读。

Con：它使用更多的内存。

Con：通过进一步抽样来概括枢轴select是昂贵的，这可以避免对某些低熵sorting的二次行为。