找到向量的第二个最小值

时间:2015-10-15 20:16:53

标签: vector scheme racket minimum

我构建了一个过程,它应该接受一个参数,一个带有数字作为条目的向量,然后返回最低值。

(define min-number
  (lambda (vec)
    (define looping
      (lambda (i v-min)
        (if (= i (vector-length vec))
            v-min
            (looping (+ i 1) (min v-min (vector-ref vec i))))))
    (looping 1 (vector-ref vec 0))

    )
  )

现在我想构造一个返回向量的第二个最小值的过程。这是应该在不将向量转换为列表的情况下完成的事情。我怎么能这样做的想法?我无法摆脱“列表思维”。我的头对我说“使用汽车”,“使用cdr”等等在这种特殊情况下不起作用。因此,任何想法将不胜感激。嗯,我想我已经涵盖了所有内容,如果有什么不清楚,请告诉我。

谢谢:)

4 个答案:

答案 0 :(得分:2)

另一种方法,类似于Óscar的答案,两者都是O(n)。这适用于任何序列,包括列表和向量!

(define (second-lowest seq)
  (define-values (_ x)
    (for/fold ((a #f) (b #f))
              ((x seq))
      (cond ((< x (or a (add1 x))) (values x a))
            ((< x (or b (add1 x))) (values a x))
            (else (values a b)))))
  x)

答案 1 :(得分:1)

如果您被允许使用内置函数,这里有一个简单的方法:找到最小值,然后查找那个最小值的下一个最小值。这就是我的意思:

(define min-number
  (lambda (vec)
    (let ((min-val (vector-argmin identity vec)))
      (vector-argmin
       (lambda (x) (if (equal? x min-val) +inf.0 x))
       vec))))

例如:

(min-number '#(5 4 1 2 3))
=> 2

答案 2 :(得分:1)

通过快速选择算法很好地解决了向量的第k个最小元素。

(define (quickselect A k)
  (define pivot (list-ref A (random (length A))))
  (define A1 (filter (curry > pivot) A))
  (define A2 (filter (curry < pivot) A))
  (cond
    [(<= k (length A1)) (quickselect A1 k)]
    [(> k (- (length A) (length A2))) (quickselect A2 (- k (- (length A) (length A2))))]
    [else pivot]))

(quickselect '(9 8 7 6 5 0 1 2 3 4) 2)  ; => 1

来自http://rosettacode.org/wiki/Quickselect_algorithm#Racket的代码

答案 3 :(得分:0)

以下是vector-select的两个版本,它们在向量v中找到第k个最小元素。这意味着(vector-select v 1)找到向量中的第二个最小元素。 vector-selectvector-select!之间的区别在于后者可能会更改向量中元素的顺序。两个过程的预期时间为O(n),其中n是向量的长度。

#lang racket
; vector-ref and vector-set! is used so often, so introduce shorter notation
(define-syntax-rule (vref  v i)   (vector-ref  v i))
(define-syntax-rule (vset! v i e) (vector-set! v i e))

; vector-select : vector index -> number
;   find the kth largest element of v
;   (where 0 <= k < n )
(define (vector-select v k) 
  (define n (vector-length v))
  (unless (<= 0 k (- n 1))
    (error 'vector-select "expected a number between 0 and the length of the vector"))
  (subvector-select! (vector-copy v) k 0 n))

; vector-select! : vector index -> number
;   find the kth largest element of v
;   (where 0 <= k < n )
;   side effect: the order of the elements may change
(define (vector-select! v k) 
  (define n (vector-length v))
  (unless (<= 0 k (- n 1))
    (error 'vector-select! "expected a number between 0 and the length of the vector"))
  (subvector-select! v k 0 n))

; subvector-select : vector index index index -> number
;   find the kth largest element of the elements v[s],v[s+1],...,v[t-1].
;   assumption: s<t  (i.e. the subvector is non-empty)
(define (subvector-select! v k s t)
  (define n (- t s)) ; length of subvector
  (cond
    [(= n 1) (unless (= k 0) (error "Error 1"))
             (vref v s)]
    [else    (define r (randomized-partion! v s t)) ; v[r] is a pivot
             (define l (- r s))                     ; number of elements left of pivot (in subvector)
             (cond
               [(= k l) (vref v r)]                             ; found it!
               [(< k l) (subvector-select! v    k     s r)]     ; the element is left  of the pivot
               [else    (subvector-select! v (- k l)  r t)])])) ; the element is right of the pivot

; randomized-partion! : vector index index -> index
;   Pick a random index between s and t, then partion the elements
;   in the subvector v[s],v[s+1],...,v[t-1] using v[r] as pivot.
;   I.e. move elements smaller than the pivot to appear before the pivot
;   and  move elements larger  than the pivot to appear after  the pivot.
;   Finally return the index of the pivot.
(define (randomized-partion! v s t)
  ;; Helper
  ; swap! : index index -> void
  ;   swap elements with index i and j
  (define (swap! i j) 
    (define vi (vref v i))          
    (vset! v i (vref v j))          
    (vset! v j vi))
  ;; Main
  (define r (+ s (random (- t s)))) ; pick random pivot index in subvector
  (define p (vref v r))             ; the pivot value
  (swap! (- t 1) r)                 ; place the pivot as the last value in the subvector
  (define i s)                      ; invariant: all elements before v[i] are <= pivot
  (for ([j (in-range s (- t 1))])   ;   loop through all elements (except the pivot)
    (when (<= (vref v j) p)         ;     if the element is non-greater than the pivot
      (swap! i j)                   ;       move it to the front of the subvector
      (set! i (+ i 1))))            ;       and update i to the next available slot
  (swap! i (- t 1))
  i)                                ;   finally put the pivot in place