DrRacket双列表输入:仅反转第一个列表的函数实现问题
搞定这个双列表反转拼接函数的小技巧
嘿,我太懂这种卡一两个小时的感觉了——对着Lisp/Scheme的递归逻辑反复试错,明明思路好像对,但结果就是不对,真的挠头!
先明确你的需求:写一个函数,接收两个列表l1和l2,返回**l1反转后拼接l2**的结果,比如(reverse '(1 2) '(3 4))要得到(2 1 3 4)对吧?
你提到已经尝试了条件判断(空列表时返回l2),但没搞定核心逻辑——问题大概率出在你处理l1反转的方式上。其实不用分开先反转再拼接,我们可以用尾递归累加器的思路,把反转和拼接一步完成,既简洁又高效!
正确的实现代码
(define (reverse l1 l2) (if (null? l1) l2 (reverse (cdr l1) (cons (car l1) l2))))
一步步拆解逻辑
咱们拿你的例子(reverse '(1 2) '(3 4))走一遍,你就懂了:
- 第一次调用:
l1是'(1 2),不是空列表,所以递归调用(reverse (cdr '(1 2)) (cons (car '(1 2)) '(3 4)))→ 也就是(reverse '(2) '(1 3 4)) - 第二次调用:
l1是'(2),还是非空,继续递归(reverse (cdr '(2)) (cons (car '(2)) '(1 3 4)))→(reverse '() '(2 1 3 4)) - 第三次调用:
l1是空列表了,直接返回l2,也就是'(2 1 3 4)——完美命中你要的结果!
这个思路的妙处在于:我们把l2当成了累加器,每一步都把l1的第一个元素放到l2的最前面,直到l1被拆完,剩下的l2就是最终结果。既不用额外写一个单独的反转函数,也不用调用append拼接,效率拉满,还不会有栈溢出的问题(Scheme会把尾递归优化成循环)。
测试几个边界情况
- 当
l1是空列表:(reverse '() '(a b c))→ 返回'(a b c),符合你的预期 - 当
l2是空列表:(reverse '(5 6 7) '())→ 返回'(7 6 5),相当于单独反转l1 - 两个列表都有多个元素:
(reverse '(x y) '(z w v))→ 返回'(y x z w v),完全正确
你之前可能踩的坑
如果之前你是先写了一个单独的反转函数,再用append拼接,比如:
;; 这种写法虽然能得到结果,但效率低,还容易写错 (define (bad-reverse lst) (if (null? lst) '() (append (bad-reverse (cdr lst)) (list (car lst))))) (define (reverse l1 l2) (append (bad-reverse l1) l2))
这种写法每次反转都要创建新的中间列表,元素多了会变慢,而且如果你的bad-reverse写得有问题(比如漏了list包裹car lst),结果就会出错。而尾递归的写法就没这些问题~
内容的提问来源于stack exchange,提问作者Collin
相关产品推荐
相关产品推荐

