Mergesort与矢量

时间:2013-12-04 20:34:20

标签: vector scheme mergesort

我正在尝试使用向量在Scheme中实现mergesort算法。我知道我可以使用的其他排序方法,但我想完成我的代码。我到目前为止的内容如下:

   (define (split v)
         (define (helper k v1 v2)
           (let ((m (floor (/ (vector-length v) 2))))
           (if (>= k m)
               (if (= k (vector-length v))
                   (cons v1 v2)
                   (helper (+ k 1) v1 (vector-append v2 (vector (vector-ref v k)))))
               (helper (+ k 1) (vector-append v1 (vector (vector-ref v k))) v2))))
         (helper 0 #() #()))

(define (merge v1 v2)
    (if (< (vector-ref v1 0) (vector-ref v2 0))
               (vector-append v1 v2)
               (vector-append v2 v1)))

(define (mergesort v)
  (if (<= (vector-length v) 1) 
      v
      (merge (mergesort (car (split v))) (mergesort (cdr (split v))))))

我非常接近我的回答,但我错过了一些东西。这里有什么帮助吗?

1 个答案:

答案 0 :(得分:2)

实现的主要障碍是您的merge函数未正确实现合并算法。在合并算法中:

  1. 您有两个指针,最初指向左侧和右侧列表的开头。
  2. 如果两个指针都位于各自列表的末尾,那么就完成了。
  3. 如果任一指​​针位于其相应列表的末尾,则输出另一个列表的其余元素。完成。
  4. 此时,两个指针都指向一个元素。如果右手元素小于左手元素,则输出右手元素,然后前进右手指针。否则,输出左侧元素,并前进左指针。转到第2步。
  5. 下面我的merge-into!函数实现了这种方法。

    除此之外,另一个主要问题是你的split函数试图逐步构建向量,遗憾的是,这是一个缓慢的过程:它必须每次都将所有元素复制到一个新的向量中。它不像cons!使用向量时,不要犹豫使用vector-set!;任何不可变的向量更新都会变得缓慢而低效,所以只需咬紧牙关并使其变得可变。 : - )


    作为参考,我从头开始编写了一个新的实现(在Racket中):

    (define (split-halves vec)
      (vector-split-at vec (quotient (vector-length vec) 2)))
    
    (define (merge lhs rhs)
      (define result (make-vector (+ (vector-length lhs)
                                     (vector-length rhs))))
      (merge-into! result lhs rhs))
    
    (define (merge-into! result lhs rhs)
      (let loop ((i 0) (j 0) (k 0))
        (define (take-left)
          (vector-set! result k (vector-ref lhs i))
          (loop (add1 i) j (add1 k)))
        (define (take-right)
          (vector-set! result k (vector-ref rhs j))
          (loop i (add1 j) (add1 k)))
        (cond ((= k (vector-length result)) result)
              ((= i (vector-length lhs))
               (take-right))
              ((= j (vector-length rhs))
               (take-left))
              ((< (vector-ref rhs j) (vector-ref lhs i))
               (take-right))
              (else
               (take-left)))))
    
    (define (mergesort vec)
      (case (vector-length vec)
        ((0 1) vec)
        (else (let-values (((lhs rhs) (split-halves vec)))
                (merge (mergesort lhs) (mergesort rhs))))))
    

    merge-into!函数允许轻松编写mergesort的变异版本:

    (define (mergesort! vec)
      (case (vector-length vec)
        ((0 1) vec)
        (else (let-values (((lhs rhs) (split-halves vec)))
                (mergesort! lhs)
                (mergesort! rhs)
                (merge-into! vec lhs rhs)))))
    

    如果您不使用Racket,您可能需要以下其他定义(需要SRFI 43;如果您没有,请参阅帖子的底部):

    (define (vector-split-at vec pos)
      (values (vector-copy vec 0 pos)
              (vector-copy vec pos (vector-length vec))))
    
    (define (add1 x)
      (+ x 1))
    

    let-valuesSRFI 11中定义。如果您没有,请使用mergesort的{​​{1}}版本:

    call-with-values

    (define (mergesort vec) (case (vector-length vec) ((0 1) vec) (else (call-with-values (lambda () (split-halves vec)) (lambda (lhs rhs) (merge (mergesort lhs) (mergesort rhs))))))) SRFI 43中定义。如果你没有,那么这是一个简化版本:

    vector-copy