删除Scheme中列表的最小元素

时间:2015-11-24 11:31:34

标签: scheme

有没有方便的方法来删除最小元素?我只能想到一种方法,找到最小值然后将其删除。但这似乎效率低下。

(define (min set)
    (let ((x (car set))
          (rest (cdr set)))
      (if (null? rest)
          x
          (if (< x (min rest))
              x
              (min rest)))))

(define (remove x set)
  (let ((s (car set)))
    (if (= x s)
        (cdr set)
        (cons s (remove x (cdr set))))))

(define (remove-min set)
    (remove (min set) set))
(remove-min `(4 1 4 5))

2 个答案:

答案 0 :(得分:1)

找到最小值然后删除它是一种有效的方法,但可以使用解释器中的minremove*内置函数以较少的代码完成。例如,在Racket中:

(define (remove-min lst)
  (remove* (list (apply min lst)) lst))

这就是它的工作原理,注意它删除了所有最小元素的出现次数:

(remove-min '(4 1 4 5 1 3))
=> '(4 4 5 3)

我们在这里讨论的是另一种效率 - 当然,我们在输入列表上迭代两次(但这对于小型列表来说不是问题,而且仍然是O(n)解决方案)。但是使用内置过程对于你自己的时间来说效率要高得多,我们不必编写和测试新代码,只需编写一些众所周知的函数。这就是在用函数式语言编写代码时应该瞄准的那种“效率”!

无论如何,如果你真的想编写自己的代码,那么你的两个实现都可以得到改进:min可以减少迭代次数(你在每一步中调用递归两次! )和remove可以一次删除所有出现的事件,并且这两个过程都需要更好地处理边缘情况(如果输入列表为空,会发生什么?) - 再次,我不建议重新发明轮子,但是你去了:

(define (min set)
  (define (loop set m)
    (cond ((null? set) m)
          ((< (car set) m)
           (loop (cdr set) (car set)))
          (else
           (loop (cdr set) m))))
  (if (null? set)
      #f
      (loop (cdr set) (car set))))

(define (remove x set)
  (cond ((null? set)
         '())
        ((= (car set) x)
         (remove x (cdr set)))
        (else
         (cons (car set) (remove x (cdr set))))))

答案 1 :(得分:0)

如果你想保持一个纯粹的功能,没有。最多你最终会同时构建两个列表,这可能会节省程序步骤但需要更多的堆栈内存。这些列表可以通过cons累加器反向构建,该累加器最后需要反向。你不能通过拨打尾部位置cons来建立列表的旧方法,因为你不确定这将是你的清单

(define (remove-min L)
  (cond ((number? L) L)
        ((or (null? L) (not (pair? L)))
         (list "undefined value for remove-min" L)) ;could be error
        ((not (number? (car L)))
         'error) 
        (else  
    (let loop ((L (cdr L))   (min (car L)) 
               (current '()) (alt (list (Car L))))
       (cond ((null? L) (reverse current))
             ((or (not (pair? L)) (not (number? (car L))))
              'error)
             ((< (car L) min) 
              (loop (cdr L)  (car L) 
                    alt      (cons (car L) alt)))
             ((= (car L) min)
              (loop (cdr L) min
                    current (cons (car L) alt)))
             (else
              (loop (cdr L)  min 
                    (cons (car L) current) (cons (car L) alt))))))))

(remove-min `(4 1 4 5)) =-> (4 4 5)
(remove-min '(1 2 3 1 2 3)) =-> (2 3 2 3)

不太纯粹的解决方案将是上面的尾部模数缺点实现。如果您不介意修改原始列表,则以下操作将起作用。

(define (remove-min! Lst)
  (cond ((number? Lst) Lst)
        ((or (null? Lst) (not (pair? Lst)))
         'error) ;could be error
        ((not (number? (car Lst)))
         'error) 
        (else 
     (let loop ((L (cdr Lst)) (min (car Lst))   (prior-cons Lst) 
               (poss (list #f))      (rests (list (cdr Lst))))
       (cond ((null? L) 
              (map (lambda (pos rest)
                      (if pos 
                          (set-cdr! pos rest) 
                          (set! Lst rest)))
                    poss
                    rests)
              Lst)
             ((or (not (pair? L)) (not (number? (car L))))
              'error)
             ((< (car L) min) 
              (loop (cdr L)     (car L)  L
                    (list prior-cons)  (list (cdr L))))
             ((= (car L) min) ;;bug here, fixed
              (if (eq? L (car rests))
                  (loop (cdr L) min prior-cons
                        poss 
                       (cons (cdar rests) 
                         (cdr rests)))                            
                  (loop (cdr L) min L
                       (cons prior-cons poss)
                       (cons (cdr L) rests))))
             (else
              (loop (cdr L) min  L  
                    poss     rests)))))))

(remove-min! (list 4 1 4 5)) =-> (4 4 5)
(remove-min (list 1 2 3 1 2 3 1 2 3)) =->(2 3 2 3 2 3)

;错误修复:)   (remove-min! (list 4 1 1 5 3 6)) =-> (4 1 5 3 6)