[我们需要一个名为nondecreaselist
的Scheme函数,该函数接收一个数字列表并输出一个列表列表,这些列表总体上具有相同的数字且顺序相同,但分为不递减的列表。
例如,如果我们输入了(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)不可调用:
(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)
,只检查一次这些情况:
(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*)))))))))))))
发布的代码存在一些问题。第二个cond
子句中没有测试表达式; if
及其子句周围有太多括号。也许最重要的问题是代码正在尝试构建一个非递减列表,该列表将被cons
转换为(nondecreaselist (cdr s))
的结果,但是当非递减序列的长度超过一个数字时,它将开始再次回到(cdr s)
,在输入列表中又过早了。
可以清除逻辑。输入为空列表时,OP代码已经在返回空列表。代替测试(null? (cadr s))
(当(cdr s)
为'()
时,cadr
无法在s
上工作),可以在代码尝试输入(null? (cdr s))
之前测试(cadr s)
。但是最好是改变这种逻辑。当输入列表包含一个元素时,仅返回包含输入列表的列表:((null? (cdr s)) (list s))
。
代替(and (not (> ;...
,可以通过测试>
并执行适当的操作来使逻辑更清晰。在这种情况下,当(> (car s) (cadr s))
应该启动一个新的子列表,并且将cons
放入到从nondecreaselist
返回的结果的子列表中。
否则,应将(car s)
添加到从nondecreaselist
返回的结果中的第一个子列表中。为此,我们需要通过以下方式构造返回列表: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))))))
使用助手功能
另一种方法是定义一个辅助函数,该函数以输入列表和累积列表为参数,返回列表列表。 helper函数将从输入列表的前面获取数字,然后将其添加到累加器中,创建一个非递减列表,或者将cons
累加的非递减列表转换为对其余列表进行运算的结果输入。
如果辅助函数lst
的输入ndl-helper
为空,则应返回包含累积的非递减列表sublst
的列表。请注意,sublst
由于其构造方式而需要在返回之前反转,如下所述。
如果累加器sublst
为空,或者输入列表中的下一个数字大于或等于sublst
中的最大数字,则应将下一个数字简单地添加到[ C0]。通过将数字sublst
放在cons
的前面,只需检查sublst
的car
,因为它始终是sublst
中的最大值(或等于最大值)。但是,由于sublst
的顺序相反,因此需要先将其反转,然后再将其添加到不断增长的列表中。
否则,sublst
不为空,并且lst
不为空,并且输入列表中的下一个数字小于sublst
中的最大数字。因此,需要启动一个新的子列表,因此通过使用空累加器sublst
在其余sublst
上调用helper函数,可以将旧的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 '()))