Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sorting 是否可以只通过一次就对列表进行快速排序?_Sorting_Haskell_Quicksort_Difference Lists - Fatal编程技术网

Sorting 是否可以只通过一次就对列表进行快速排序?

Sorting 是否可以只通过一次就对列表进行快速排序?,sorting,haskell,quicksort,difference-lists,Sorting,Haskell,Quicksort,Difference Lists,我正在学习haskell,我看到的函数定义是: quickSort (x : xs) = (quickSort less) ++ (x : equal) ++ (quickSort more) where less = filter (< x) xs equal = filter (== x) xs more = filter (> x) xs quickS

我正在学习haskell,我看到的函数定义是:

quickSort (x : xs) = (quickSort less) ++ (x : equal) ++ (quickSort more)
                 where less = filter (< x) xs
                       equal = filter (== x) xs
                       more = filter (> x) xs
quickSort(x:xs)=(少快速排序)+(x:equal)++(多快速排序)
其中less=过滤器(x)xs

是否可以只遍历一次列表而不是3次来编写它?

它似乎没有任何改进,除了:

qs (x:xs) = let (a,b) = partition (< x) xs in (qs a) ++ [x] ++ (qs b)
qs(x:xs)=let(a,b)=分区(
你的意思是这样的

quicksort [] = []
quicksort (x:xs) = quicksort less ++ (x : equal) ++ quicksort more
  where (less, equal, more) = partition3 x xs

partition3 _ [] = ([], [], [])
partition3 x (y:ys) =
  case compare y x of
    LT -> (y:less, equal, more)
    EQ -> (less, y:equal, more)
    GT -> (less, equal, y:more)
  where (less, equal, more) = partition3 x ys

请注意,这并不是真正的快速排序,因为真正的快速排序已经准备就绪。

虽然很晚了,但这里有一个版本应该不会泄漏太多空间(并且似乎比这里的其他3向版本快两倍):

这解决了使用元组时可能出现的问题,其中
let(a,b)=……
实际上被转换为
let t=。。。;a=fst;b=snd t
这导致了这样一种情况,即即使在
a
被消费和处理之后,它仍然作为元组
t
的一部分保持活着,以便从中读取
b
,当然这是完全不必要的。这就是所谓的“瓦德勒对空间泄漏”问题。或者GHC(使用
-O2
)比这更聪明。:)


此外,这显然使用了差异列表方法(谢谢,hammar),这也使它更高效(大约比使用元组的版本快两倍)。我认为
part
使用累加器参数,因为它以相反的顺序构建它们。

Quicksort平均具有
O(n lg n)
复杂性…复杂性与所做比较的数量有关,上面的版本将比通过遍历一次来划分列表的版本多3倍。@newacct,它不仅仅是遍历列表;它是在遍历时比较每个元素;这就是为什么。@ivanm,是的,复杂性是一样的,平均是O(n logn)。但它是O(n^2),最坏的情况。然而,不管这个事实如何,这个问题是合理的,算法的实现通常是通过常数因子的大小来衡量的。@ivanm,O(n)表示法是一种衡量复杂性的方法。这并不意味着复杂性是相同的。假设我用英里来测量距离,这样对我来说更容易。这并不意味着我要花同样的时间去隔壁和附近的购物中心,那太棒了。为什么你认为它没有改善任何事情?它只遍历列表一次。因此,比较要小得多。@qq191:这个定义假设没有重复的值,这就是为什么原始版本有三个过滤器@乔纳斯·杜雷格:等等,你是对的;它们进入
b
分区。这很整洁。我提到的原始算法也没有进行就地快速排序。我假设in-place意味着列表被修改的可变版本。这不是应该泄漏空间的“Wadler对”问题吗?(根据他的技术IIRC,我发布了另一个应该没有这个问题的版本)。@WillNess:你的版本肯定更有效,特别是因为它使用差异列表而不是
(++)
进行附加。我的可能会分配多一点,因为它使用元组,但我认为它不应该泄漏空间。不过,我对“瓦德勒对”问题并不熟悉。你有链接吗?谷歌似乎也不知道。谷歌“Wadler pair space leak”基本上是关于
let(a,b)=span…
之类的事情,被翻译成
let p=span。。。;a=fst$p;b=snd$p
这导致
p
被保留为
b
,即使
a
已经被消费。配对…:)(我的意思是,元组…IIRC这正是这个“泄漏”东西的本意)。顺便说一句,我认为你的版本是真正的惯用Haskell解决方案;太糟糕了,一个编译器不能自动完成转换,我不得不手工编写代码。我们自然地用变量的元组表示并行“赋值”;这是哈斯克尔的错,他没有一个明确的概念,强迫我们使用一个乱七八糟的词,然后为此惩罚我们……cf。一个稳定的排序变量位于的底部。
qsort3 xs = go xs [] 
  where
    go     (x:xs) zs       = part x xs zs [] [] []
    go     []     zs       = zs
    part x []     zs a b c = go a ((x : b) ++ go c zs)
    part x (y:ys) zs a b c =
        case compare y x of
                  LT -> part x ys zs (y:a) b c
                  EQ -> part x ys zs a (y:b) c
                  GT -> part x ys zs a b (y:c)