首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >方案:实现快速排序

方案:实现快速排序
EN

Stack Overflow用户
提问于 2017-04-18 13:45:17
回答 2查看 4K关注 0票数 1

我正在尝试使用一个快速的排序方案,这里的一些人已经帮我修复了我的split函数,现在我请求您帮助将所有的东西组合成一个工作的算法。

到目前为止,我的代码如下:

代码语言:javascript
复制
(define quick-sort (lambda (lst)

                 (define pivot (lambda (lst)
                                 (if (null? lst)
                                     null
                                     (car lst))))
                 (define split (lambda (lst pivot)
                                 (define lst1 null)
                                 (define lst2 null)
                                 (define split-helper (lambda (lst pivot lst1 lst2)
                                                        (if (null? lst)
                                                            (list lst1 lst2)
                                                            (if (<= (car lst) pivot)
                                                                (split-helper (cdr lst) pivot (cons (car lst) lst1) lst2)
                                                                (split-helper (cdr lst) pivot lst1 (cons (car lst) lst2))))))
                                 (split-helper lst pivot lst1 lst2)))

                 (if (null? lst)
                            null
                            (append (quick-sort (car (split lst (pivot lst)))) (quick-sort (cdr (split lst (pivot lst))))))))

正如你所看到的,我选择枢轴只是为了成为列表中的第一个元素,我面临的问题是当这个枢轴是列表中最小的元素时,程序会陷入一个无限循环,因为它让程序一次又一次地选择相同的枢轴。

而且,它目前的实现方式使得它实际上是无效的,因为split函数在每个quick-sort的惰性中都用相同的lst被调用两次,但是我对Scheme没有足够好的控制,无法用其他方式编写它。

我看到了一些关于快速排序的帖子,但是它们的实现有点不同,我宁愿尝试纠正我自己的实现,也不愿抄袭其他人的作品。

谢谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-04-18 22:49:02

删除过多的lambdas、别名、绑定和重新格式化,但没有更改或注释语义(Sylwester已经指出了错误):

代码语言:javascript
复制
(define (quick-sort lst)
   (define (pivot lst)
      (if (null? lst)
         '()
         (car lst) ))
   (define (split lst pivot)
      (let split-helper ((lst lst)         ; Named let instead of internal
                         (lst1 '())        ; definition
                         (lst2 '()) )
         (if (null? lst)
            (cons lst1 list2)
            (if (<= (car lst) pivot)
               (split-helper (cdr lst)
                             (cons (car lst) lst1)
                             lst2)
               (split-helper (cdr lst)
                             lst1
                             (cons (car lst) lst2) )))))
   (if (null? lst)
      '()
      (let ((spl (split lst (pivot lst)))) ; Memoization of the `split`
         (append (quick-sort (car spl))
                 (quick-sort (cdr spl)) ))))

我想你是在尝试实现一个partition

代码语言:javascript
复制
(define (partition pred xs)
   (let part ((ps '()) (ns '()) ; Initial "positives" `ps`, and "negatives" `ns`
              (xs' xs) )
      (if (null? xs')
         (cons ps ns)             ; Returning pair of lists
         (let ((x (car xs')))     ; Memoization of `(car lst)`
            (if (pred x)
               (part (cons x ps) ns (cdr xs'))
               (part ps (cons x ns) (cdr xs')) )))))

(define (quicksort xs)
   (if (null? xs) '()
      (let* ((x (car xs))
             (pn (partition               ; Memoization of `partition`
                    (lambda (x')
                       (< x' x) )
                    (cdr xs) )))
         (append (quicksort (car pn))      ; Extracting positives from pair
                 (list x)                  ; Pivot
                 (quicksort (cdr pn)) )))) ; Negatives


(display
   (quicksort (list 4 2 3 5 1)) )    ; (1 2 3 4 5)

在诸如Scheme这样的严格语言中,part效率低下;它在每一个递归步骤中都复制它的所有三个参数。通常,以基本折叠(如filtermap )为基础的直截了当的公式最有效。使用filter更有效的实现

代码语言:javascript
复制
(define (quicksort xs)
   (if (null? xs) '()
      (let ((x (car xs))
            (xs' (cdr xs)) )
         (append (quicksort
                    (filter (lambda (x')
                               (< x' x) )
                            xs'))
                 (list x)
                 (quicksort
                    (filter (lambda (x')
                               (>= x' x) )
                            xs'))))))

众所周知,这种策略在函数式语言中非常简单地表达。

在懒惰的Haskell中,单次遍历partition实际上比filter执行两次更有效。

代码语言:javascript
复制
select :: (a -> Bool) -> ([a], [a]) -> a -> ([a], [a])
select pred (ps, ns) x | pred x    = (x : ps, ns)
                       | otherwise = (ps, x : ns)

partition :: (a -> Bool) -> [a] -> ([a], [a])
partition pred  =  foldl (select pred) ([], [])

quicksort :: Ord a => [a] -> [a]
quicksort []       = []
quicksort (x : xs) = let (lt, gt) = partition (< x) xs
                     in  quicksort lt ++ [x] ++ quicksort gt
票数 2
EN

Stack Overflow用户

发布于 2017-04-18 14:39:14

说到快速排序,这是一个经典的错误。您的枢轴不应该是分区的一部分。这样,一个元素列表就会生成两个空分区,一个在支点之前,一个在枢轴之后。

做两次同样的手术。使用let缓冲拆分结果并使用该变量两次。

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

https://stackoverflow.com/questions/43474008

复制
相关文章

相似问题

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