我对Scheme很新,我在编写函数时遇到了麻烦。我有一个图G给我作为列表,格式如下:((node1 node2 weight1)(node3 node4 weight2)...)。我正在尝试编写一个函数,以这种格式返回此图中所有节点(V)的列表:(node1 node2 node3 ...)。该函数只能将图形(G)作为输入。
所以我认为我可以通过在G中将每个嵌套列表的第一个和第二个元素添加到V来递归地执行此操作。这是我写的:
(define nodes-of
(lambda (G)
(if (null? G)
()
(begin (add-to-set (cadar G) (nodes-of (cdr G)))
(add-to-set (caar G) (nodes-of (cdr G))))))
我认为这是错误的,因为第一次递归只涉及(cadar G)而第二种涉及(caar G),并且返回值将仅由开始时的第二个语句设置(如果我没有弄错的话) )。
add-to-set是我之前为家庭作业编写的一个函数,如果列表中不存在元素,它会向列表添加元素。 (例如:add-to-set n S,这会将n添加到S)
有人可以帮我这个吗? (顺便说一下,我不允许使用多个let,让*或设置)
答案 0 :(得分:3)
嗯,你是对的,你可以递归地做,并且你的代码非常接近。回想一下,每个递归过程都需要一个你知道答案的基本状态,以及每次递归时降低问题复杂性的方法。
在处理列表的情况下,您的基本案例是空列表,这就是您要检查null的原因。然后,缩减公式将中断一个列表,然后在剩余部分上调用该过程。所以,就像我说的那样,你很亲密。
然后意识到,由于您的数据是定期构建的,因此您可以将图表视为普通列表。您不需要递归到列表的每个元素,只需要对每个元素执行两个操作并将结果放在列表中。
(define nodes-of
(lambda (G)
(if (null? G) ;<-- have we reached the base case yet?
'() ;<-- if yes, return null so our cons will build a list
(cons (caar G) (cons (cadar G) (nodes-of (cdr G))))))) ;<-- if not, keep building the list by grabbing the things we want from each element, then reducing the list
如果您愿意,也可以使用let
。
(define nodes-of
(lambda (G)
(if (null? G)
'()
(let ((n1 (caar G))
(n2 (cadar G)))
(cons n1 (cons n2 (nodes-of (cdr G))))))))
在您的情况下,您将使用我add-to-set
使用的cons
。一旦我们到达基本情况,所有对add-to-set
的调用将能够从最后一个调用开始进行评估,然后再从堆栈返回到第一个调用。
|cons n3 '() | 2 => (n3)
|cons n2 [result of 2] | 1 => (n2 n3)
|cons n1 [result of 1] | 0 => (n1 n2 n3)