#scheme #racket #r5rs
#схема #рэкет #r5rs #ракетка
Вопрос:
Я знаю, что общий код должен возвращать последние n-е элементы списка, однако я не понимаю процесс, например, в каждой строке, что происходит (и почему, если возможно)?
(define (last-n lst n)
(define (help-func lst drop)
(cond
((> drop 0)
(help-func (cdr lst ) (- drop 1)))
(else
(cdr lst ))))
(if (= (length lst ) n )
lst
(help-func lst (- (length lst ) 1 n ))))
Ответ №1:
Есть небольшая ошибка, когда n
больше длины списка, вы должны возвращать весь список (или сигнализировать об ошибке), я исправил это. Вот разбивка кода:
(define (last-n lst n)
(define (help-func lst drop)
(cond
; iterate while there are elements to drop
((> drop 0)
; advance on the list, and we're one
; element closer to reach our target
(help-func (cdr lst) (- drop 1)))
(else
; else we reached the point we wanted, stop
(cdr lst))))
; if n is at least as big as the list
(if (>= n (length lst))
; return the whole list
lst
; else calculate how many elements
; we need to drop and start the loop
(help-func lst (- (length lst) 1 n))))
К вашему сведению, Racket уже имеет эту функциональность, просто используйте take-right
встроенную процедуру, это будет даже быстрее, требуя одного прохода по списку (вы вызываете length
пару раз, и в умном алгоритме это было бы ненужно)
Комментарии:
1. Это не так уж плохо. Это O (n), и лучшее, что вы могли бы сделать, это O (n). Очевидная вещь, которую нужно сделать, это кэшировать
length
, но помимо этого вы не увидите большого улучшения по сравнению с версией с курсором, которая выполняет только один проход.2. Конечно, все это в пределах одной и той же сложности O (n). Но я испытываю зуд каждый раз, когда вижу,
length
используется для перебора списка, даже если только один раз: P