首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么我的Haskell选择排序实现非常快?

为什么我的Haskell选择排序实现非常快?
EN

Stack Overflow用户
提问于 2020-01-05 18:50:04
回答 1查看 331关注 0票数 4

我实现了选择排序,并将其与Data.List的排序进行了比较。它比Data.List的排序快几个数量级。如果我将它应用于10,000个随机生成的数字,结果如下:

代码语言:javascript
复制
 ✓ in 1.22µs: Selection sort
 ✓ in 9.84ms: Merge sort (Data.List)

这不可能是对的首先,我想也许merge sort的中间结果会被缓存,而selection sort使用这些结果要快得多。即使我注释掉了merge sort和only time selection sort,它还是这么快。我还验证了输出,并且它是正确排序的。

是什么导致了这种行为?

我使用下面的代码来测试:

代码语言:javascript
复制
{-# LANGUAGE BangPatterns #-}

module Lib
    ( testSortingAlgorithms
    ) where

import System.Random (randomRIO)
import Text.Printf
import Control.Exception
import System.CPUTime
import Data.List (sort, sortOn)


selectionSort :: Ord a => [a] -> [a]
selectionSort [] = []
selectionSort nrs = 
  let (smallest, rest) = getSmallest nrs
  in smallest : selectionSort rest
  where getSmallest :: Ord a => [a] -> (a, [a])
        getSmallest [a] = (a, [])
        getSmallest (a:as) = let (smallest, rest) = getSmallest as
                             in if smallest > a then (a, smallest : rest)
                                                else (smallest, a : rest)


main :: IO ()
main = testSortingAlgorithms


testSortingAlgorithms :: IO ()
testSortingAlgorithms = do
    !list' <- list (10000)
    results <- mapM (timeIt list') sorts
    let results' = sortOn fst results
    mapM_ (\(diff, msg) -> printf (msg) (diff::Double)) results'
    return ()


sorts :: Ord a => [(String, [a] -> [a])]
sorts = [
        ("Selection sort", selectionSort)
      , ("Merge sort (Data.List)", sort)
    ]


list :: Int -> IO [Int]
list n = sequence $ replicate n $ randomRIO (-127,127::Int)


timeIt :: (Ord a, Show a) 
       => [a] -> (String, [a] -> [a]) -> IO (Double, [Char])
timeIt vals (name, sorter) = do
    start <- getCPUTime
    --v <- sorter vals `seq` return ()
    let !v = sorter vals
    --putStrLn $ show v
    end   <- getCPUTime
    let (diff, ext) = unit $ (fromIntegral (end - start)) / (10^3)
    let msg = if correct v 
              then (" ✓ in %0.2f" ++ ext ++ ": " ++ name ++ "\n") 
              else (" ✗ in %0.2f" ++ ext ++ ": " ++ name ++ "\n") 
    return (diff, msg)


correct :: (Ord a) => [a] -> Bool
correct [] = True
correct (a:[]) = True
correct (a1:a2:as) = a1 <= a2 && correct (a2:as)


unit :: Double -> (Double, String)
unit v | v < 10^3 = (v, "ns")
       | v < 10^6 = (v / 10^3, "µs")
       | v < 10^9 = (v / 10^6, "ms")
       | otherwise = (v / 10^9, "s")
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-01-05 19:35:00

你写

代码语言:javascript
复制
let !v = sorter vals

这是“严格的”,但仅限于WHNF。因此,您只需要计算查找列表中最小元素所需的时间,而不是对整个列表进行排序所需的时间。选择排序就是这样开始的,所以对于这个不正确的基准来说,它是“最佳的”,而mergesort做了更多的工作,如果你只看第一个元素,这些工作是“浪费的”。

票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59599094

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档