查找列表的最小值和最大值

Finding min and max of list

(define (find-extrema-helper xs max min length)
  (if (null? xs)
      (printf "The maximum of your list is ~a and the minimum is ~a." max min)
      (let ((head (car xs))
            (tail (cdr xs)))
        (when (> head max)
          (set! max head))
        (when (< head min)
          (set! min head))
        (when (not (null? length))
          (set! length (- length 1)))
        (when (equal? length 0)
          (set! xs null))
        (find-extrema-helper tail max min length))))

(define (find-extrema xs)
  (let ((max (car xs))
        (min (car xs)))
    (find-extrema-helper xs max min null)))

(define (find-extrema-sublist-helper xs first length)
  (if (> first 0)
      (let ((head (car xs))
            (tail (cdr xs))
            (first (- first 1)))
        (find-extrema-sublist tail first length))
      (let  ((max (car xs))
             (min (car xs)))
        (find-extrema-helper xs max min length))))

(define (find-extrema-sublist xs first last)
  (set! last (- last first))
  (find-extrema-sublist-helper xs first last))

一切正常,除了在查找子列表的最大值时,就像长度变量被忽略并且正在查找整个列表的最大值。感谢您的帮助。

试试这个:

(define (find-extrema xs)
    (if (null? xs) "Empty list."
        (printf "The maximum of your list is ~a and the minimum is ~a."
            (apply max xs)
            (apply min xs))))
  • 如果您的函数需要列表作为参数,则此列表可以为空。 null? returns #true,如果 xs 是空列表。 (null? '()) => #t.
  • 如果您需要将某个数字与零进行比较,请改用 (= 0 number)
  • 方案具有内置函数 min and max,但您不能在列表中使用它们:(max 1 2 3 4 5) => 5(max '(1 2 3 4 5)) => error
  • 但是 apply 正是您所需要的。 (apply max '(1 2 3 4 5)) => (max 1 2 3 4 5) => 5.
  • 顺便说一句,当您命名变量时,请检查该名称是否尚未被使用(例如 minmax , length, first, last)。在 REPL 中输入该名称并查看结果: max => #<procedure:max>。 Scheme 允许您在给定范围内更改该变量的值,但您将丢失以前的值。比较这两个函数:
(define (f1 xs first)
  (first xs))

(define (f2 xs first-elem)
  (first xs))

,这样称呼:

> (f1 '(1 2 3) 1)
> (f2 '(1 2 3) 1)

编辑:没有内置最小值和最大值的解决方案:


    (define (find-extrema-help xs min-num max-num)
      (if (null? xs)
          (printf "The maximum of your list is ~a and the minimum is ~a." max-num min-num)
          (find-extrema-help (cdr xs)
                             (if (< (car xs) min-num) (car xs) min-num)
                             (if (> (car xs) max-num) (car xs) max-num))))
    
    (define (find-extrema xs)
      (if (null? xs) "Empty list."
          (find-extrema-help (cdr xs)
                             (car xs)
                             (car xs))))

查找极值子列表:


    (define (drop xs number)
      (cond ((null? xs) xs)
            ((= 0 number) xs)
            (else (drop (cdr xs) (- number 1)))))
    
    (define (take xs number)
      (cond ((null? xs) '())
            ((= number 0) '())
            (else (cons (car xs) (take (cdr xs) (- number 1))))))
    
    (define (find-extrema-sublist xs down-index top-index)
      (let ((len (- top-index down-index)))
        (find-extrema (take (drop xs down-index)
                            len))))

您几乎从不需要“设置!”,并且您应该递归列表的结构,而不是它的长度。

对于非空列表,最大值为

  • car,如果列表只有一个元素(即它的尾部是空列表),
  • car 中的最大值和 cdr 中的最大值,如果列表更长。

(define (max-element x y) (if (> x y) x y))

(define (max-list ls)
    (if (null? (cdr ls))
        (car ls)
        (max-element (car ls) (max-list (cdr ls)))))

同样的原则也适用于最小值。

(define (min-element x y) (if (< x y) x y))

(define (min-list ls)
    (if (null? (cdr ls))
        (car ls)
        (min-element (car ls) (min-list (cdr ls)))))

现在你需要两者,所以你应该制作一对(或其他一些结构)。
简单的方法是使用前面的两个函数,

(define (extrema ls) (cons (min-list ls) (max-list ls)))

但这很低效,因为它遍历了列表两次。

让我们做得更好。
这是同时应用于两个值的相同想法:

(define (extrema ls)
    (if (null? (cdr ls))
        (cons (car ls) (car ls))
        (let ((cdr-extrema (extrema (cdr ls)))
              (head (car ls)))
             (cons (min-element head (car cdr-extrema))
                   (max-element head (cdr cdr-extrema)))))