Неубывающий список списков в Схеме? - PullRequest
0 голосов
/ 08 апреля 2020

Нам нужна функция Scheme, которая называется nondecreaselist, которая берет список чисел и выводит список списков, которые в целом имеют одинаковые номера в том же порядке, но сгруппированы в неубывающие списки.

Например, если у нас есть ввод (1 2 3 4 1 2 3 4 1 1 1 2 1 1 0 4 3 2 1), вывод должен быть:

((1 2 3 4) (1 2 3 4) (1 1 1 2) (1 1) (0 4) (3) (2) (1))

Как бы вы это реализовали? Я знаю, что мы должны использовать рекурсию. Моя попытка до сих пор:

(define (nondecreaselist s) 
  (cond ((null? s) '())
        ((cons (cons (car s)
                     ((if (and (not (null? (cadr s)))
                               (not (> (car s) (cadr s))))
                          ((cadr s))
                          ('()))))
               (nondecreaselist (cdr s))))))

Однако, это дает мне ошибку:

(int) не вызывается:

Ответы [ 2 ]

1 голос
/ 09 апреля 2020
(define decrease-list
  (lambda (l)
    ((lambda (s) (s s l cons))
     (lambda (s l col)
       ;; limitcase1: ()
       (if (null? l)
           (col '() '())
           ;; limitcase2: (a1)
           (if (null? (cdr l))
               (col l '())
               (let ((a1 (car l)) (a2 (cadr l)))
                 ;; limitcase3: (a1 a2)
                 (if (null? (cddr l))
                     (if (>= a2 a1)
                         (col l '())
                         (col (list a1) (list (cdr l))))
                     ;; most usual case: (a1 a2 ...)
                     (s s (cdr l)
                        (lambda (g l*)
                          (if (>= a2 a1)
                              (col (cons a1 g) l*)
                              (col (list a1) (cons g l*)))))))))))))

1 ]=> (decrease-list '(1 2 3 4 1 2 3 4 1 1 1 2 1 1 0 4 3 2 1))
;Value: ((1 2 3 4) (1 2 3 4) (1 1 1 2) (1 1) (0 4) (3) (2) (1))

Я не комментировал это, если у вас есть вопросы, которые вы можете задать, но я думаю, что вы также можете изучить код, который я написал для вас сейчас.

Обратите также внимание, что можно рассмотреть предельные случаи () и (a1) из l oop и проверьте эти случаи только один раз:

(define decrease-list
  (lambda (l)
    ;; limitcase1: ()
    (if (null? l)
        '()
        ;; limitcase2: (a1)
        (if (null? (cdr l))
            (list l)
            ((lambda (s) (s s l cons))
             (lambda (s l col)
               (let ((a1 (car l)) (a2 (cadr l)))
                 ;; limitcase3: (a1 a2)
                 (if (null? (cddr l))
                     (if (>= a2 a1)
                         (col l '())
                         (col (list a1) (list (cdr l))))
                     ;; most usual case: (a1 a2 ...)
                     (s s (cdr l)
                        (lambda (g l*)
                          (if (>= a2 a1)
                              (col (cons a1 g) l*)
                              (col (list a1) (cons g l*)))))))))))))
1 голос
/ 09 апреля 2020

Есть несколько проблем с размещенным кодом. Во втором предложении cond нет тестового выражения; вокруг if и его пунктов слишком много скобок. Возможно, наиболее существенной проблемой является то, что код пытается создать неубывающий список, который должен быть cons отредактирован до результата (nondecreaselist (cdr s)), но когда неубывающая последовательность имеет длину более одного числа, это начинается снова слишком рано в списке ввода, вернувшись обратно к (cdr s).

Исправление кода операции

Лог c можно очистить. ОП-код уже возвращает пустой список, когда ввод является пустым списком. Вместо проверки (null? (cadr s)) (когда (cdr s) равен '(), cadr не будет работать на s), можно протестировать (null? (cdr s)) до того, как код попытается (cadr s). Но еще лучше перенести эту логику; если входной список содержит один элемент, просто верните список, содержащий входной список: ((null? (cdr s)) (list s)).

Вместо (and (not (> ;... логика c может быть прояснена путем тестирования на > и выполнения соответствующее действие. В этом случае, когда (> (car s) (cadr s)) должен быть запущен новый подсписок, и cons добавляется в список подсписков, который является результатом, возвращаемым из nondecreaselist.

В противном случае, (car s) следует добавить к первый подсписок в результате вернулся с nondecreaselist. Чтобы выполнить sh, нам нужно построить список возврата путем cons ввода s в первый подсписок и затем cons, переместив этот новый подсписок обратно в cdr списка подсписков, который является результат, возвращаемый из nondecreaselist.

Вот некоторый пересмотренный код:

(define (nondecreaselist s) 
  (cond ((null? s) '())
        ((null? (cdr s)) (list s))
        ((> (car s) (cadr s))
         (cons (list (car s))
               (nondecreaselist (cdr s))))
        (else
         (let ((next (nondecreaselist (cdr s))))
           (cons (cons (car s)
                       (car next))
                 (cdr next))))))

Использование вспомогательной функции

Другой подход заключается в определении вспомогательной функции, которая принимает список ввода и список накопления в качестве аргументов, возвращая список списков. Вспомогательная функция будет брать числа из передней части списка ввода и либо добавлять их в накопитель, создавая неубывающий список, либо получит cons накопленный неубывающий список в результате работы с остальной частью input.

Если вход lst для вспомогательной функции ndl-helper пуст, то должен быть возвращен список, содержащий накопленный неубывающий список sublst. Обратите внимание, что sublst необходимо будет изменить до его возвращения из-за способа его построения, как описано ниже.

Если аккумулятор sublst пуст или если следующий номер в списке ввода больше или равно наибольшему числу в sublst, тогда следующее число должно быть просто добавлено к sublst. При cons введении числа в начало sublst необходимо проверить только car из sublst, поскольку это всегда будет наибольшее (или равное наибольшему) значение в sublst. Но, поскольку sublst находится в обратном порядке, перед добавлением его в растущий список списков его необходимо перевернуть.

В противном случае lst не пусто, а sublst не пусто, и следующий номер в списке ввода меньше самого большого числа в sublst. Таким образом, новый подсписок должен быть запущен, поэтому старый sublst переворачивается и cons обращается к результату оставшегося вычисления, выполненного путем вызова вспомогательной функции для оставшихся lst с пустым аккумулятором sublst:

(define (nondecreaselist-2 lst)
  (define (ndl-helper lst sublst)
    (cond ((null? lst) (list (reverse sublst)))
          ((or (null? sublst)
               (>= (car lst) (car sublst)))
           (ndl-helper (cdr lst) (cons (car lst) sublst)))
          (else
           (cons (reverse sublst) (ndl-helper lst '())))))
  (ndl-helper lst '()))

Обе функции работают:

> (nondecreaselist '(1 2 3 4 1 2 3 4 1 1 1 2 1 1 0 4 3 2 1))
((1 2 3 4) (1 2 3 4) (1 1 1 2) (1 1) (0 4) (3) (2) (1))
> (nondecreaselist-2 '(1 2 3 4 1 2 3 4 1 1 1 2 1 1 0 4 3 2 1))
((1 2 3 4) (1 2 3 4) (1 1 1 2) (1 1) (0 4) (3) (2) (1))
...