我在这里很难做出稳定的快速排序。但是,我的快速排序似乎很稳定。
quicksortBy _ []=[]
quicksortBy key (pivot:rest)=
(quicksortBy key [little|little<-rest, key little < key pivot])
++ [pivot] ++
(quicksortBy key [big|big<-rest, key big >= key pivot])
然后我这样做:
*Main> let items = [(4,0),(1,1),(10,2),(6,3),(4,4),(6,5), (1,6)]
*Main> quicksortBy fst items
[(1,1),(1,6),(4,0),(4,4),(6,3),(6,5),(10,2)]
通过使用第一个项目作为枢轴,重复项将转到右侧。这是错误的,还是人们不使用它,因为它对排序数据效率低下。还是我发现了新的东西?
答案 0 :(得分:3)
是的,您描述的算法是稳定的,通常被称为“天真”快速排序。该算法的问题在于它需要额外的O(n)空间来对数组进行排序。更节省空间的quicksort版本使用就地交换来修改数组,这会破坏稳定性,但会降低O(log n)的空间成本 - 实际上只是递归调用的堆栈。
答案 1 :(得分:1)
你的快速排序稳定的原因是(因为你是一种函数式语言)它将元素(按顺序)复制到一个新的数组中,或者在每一步中复制三个元素。这在时间和空间上效率都相当低,但(正如你所发现的那样)它是稳定的。使用可变数组的更有效的快速排序将数组从外部就地分区,在每个级别只需要一次遍历数组,并且只使用一个额外的存储元素来交换元素(并且,使用整数数组,可以实际上绕过甚至使用xor交换)。
答案 2 :(得分:1)
是的,它很稳定。 Quicksort的内部循环非常有效,因此您的算法也可能比其他稳定的排序算法(如mergesort)更快,但我猜测概率很低。 缺点是,它比mergesort消耗更多的空间(用于存储索引)。 通过查看比较函数,我猜它在具有许多等效键的数组上表现非常差,因为它们每个都需要两个分支。
总而言之,自由研究并在应用中使用mergesort。