Scheme 如何确定列表中的原子数是偶数还是奇数

Scheme 如何确定列表中的原子数是偶数还是奇数,scheme,Scheme,tScheme新手问题: 我需要使用递归确定一个列表是否包含偶数或奇数个原子。我知道最简单的方法是获取列表长度并确定它是偶数还是奇数,但我想看看如何使用递归来完成它 (oddatom (LIST 'x 'y 'v 'd 'r 'h 'y)) 应返回#t,而 (oddatom '((n m) (f p) l (u k p))) 应返回#f 感谢您的帮助。我愿意: (define (oddatom lst) (cond ((null? lst) #f)

tScheme新手问题:

我需要使用递归确定一个列表是否包含偶数或奇数个原子。我知道最简单的方法是获取列表长度并确定它是偶数还是奇数,但我想看看如何使用递归来完成它

(oddatom 
  (LIST 'x 'y 'v 'd 'r 'h 'y))
应返回
#t
,而

(oddatom 
  '((n m) (f p) l (u k p)))
应返回
#f

感谢您的帮助。

我愿意:

(define (oddatom lst)
  (cond
    ((null? lst)       #f)
    ((not (pair? lst)) #t)
    (else (not (eq? (oddatom (car lst)) (oddatom (cdr lst)))))))
这意味着:

  • 空列表不是奇数(#f)
  • 原子是奇数(#t)
  • 否则,列表中的
    car
    cdr
    中可能只有一个是奇数(异或)
  • 测试用例(在Racket中),包括不正确的列表:

    (require rackunit)
    (check-equal? (oddatom (list 'x 'y 'v 'd 'r 'h 'y)) #t)
    (check-equal? (oddatom '((n m) (f p) l (u k p))) #f)
    (check-equal? (oddatom '(a (b) c)) #t)
    (check-equal? (oddatom (cons 1 2)) #f)
    (check-equal? (oddatom 1) #t)
    (check-equal? (oddatom '(1 (2 . 3))) #t)
    

    以下是我的解决方案版本:

    (define (oddatom? lst)
      (let recur ((odd #f)
                  (x lst))
        (cond ((null? x) odd)
              ((pair? x) (recur (recur odd (car x)) (cdr x)))
              (else (not odd)))))
    
    我喜欢,但我认为值得提供一个尾部递归版本来维护自己的堆栈。请注意,这是将非尾部递归转换为尾部递归的练习,这是Scheme中某些算法的重要技术。不过,在这种情况下,这可能并不那么重要,克里斯·杰斯特·杨(Chris Jester Young)答案中的代码确实让人感觉更自然。因此,将此视为一种练习,不一定是一种重大改进

    这里的想法是,内部函数,
    odd?
    ,获取一个事物列表,以及一个值,该值指示到目前为止是否已看到奇数个原子(空列表除外)

    (定义(oddaom?东西)
    (让单数?((事物(列表事物))
    (结果#f))
    (续)
    我们看不到东西了。我们看到的东西是奇数吗?
    ((空?事物)
    结果)
    我们的事物列表的形式是((x.y)…),所以我们继续循环
    ;;;(x y…),结果为*相同*值,因为我们没有
    “看到”x或y了,我们只是“打开”了它们。
    ((配对?(汽车用品))
    (奇数?(cons(caar事物)(cons(cdar事物)(cdr事物))结果)
    我们的事物列表的形式是(()…),所以我们继续循环
    ;;(…),结果为*相同*值,因为我们没有“看到”任何结果
    额外的原子。
    ((空?(汽车用品))
    (奇数?(cdr事物)结果)
    我们的事物列表的形式是(…),所以我们在(…)上递归,
    但结果是一个翻转的值,因为我们又看到了一个原子。
    (其他
    (奇数?(cdr事物)(非结果‘‘‘‘‘‘)
    
    最后两种情况可以组合在一起,使第二个递归参数基于
    (null?(car things))
    的值,如下所示:

    (定义(oddaom?东西)
    (让单数?((事物(列表事物))
    (结果#f))
    (续)
    ((空?事物)
    结果)
    ((配对?(汽车用品))
    (奇数?(cons(caar事物)(cons(cdar事物)(cdr事物))结果)
    (其他
    (奇数?(cdr物品)(如果(空)(汽车物品))
    结果
    (不是结果‘‘‘‘‘‘)
    
    这里有一个:

    (define (odd-atom? obj)
      (and (not (null? obj))
           (or (not (pair? obj))
               (let ((this? (odd-atom? (car obj)))
                     (rest? (odd-atom? (cdr obj))))
                 (or (and (not this?) rest?)
                     (and (not rest?) this?))))))
    
    或者,从@uselpa学习来简化“或”这个?上面的rest?逻辑,另一个:

    (define (odd-atom? obj)
      (and (not (null? obj))
           (or (not (pair? obj))
               (not (eq? (odd-atom? (car obj))
                         (odd-atom? (cdr obj)))))))
    
    如果
    '()
    是一个原子(就像在CommonLisp中
    '()
    也是
    T
    ),那么它应该是
    (奇数原子?)(()())
    \T


    我不确定这是对这个问题的正确解释。你的答案不是计算亚名单中的原子,你可能是对的。我会更新我的答案。克里斯的答案实际上是平面列表的尾部递归。我记得我检查过类似版本的
    count atoms
    和类似于您的代码的性能,我很惊讶在我的测试中,较短的代码战胜了更聪明的算法,除了
    cdr
    中所有原子的最坏情况。对于平面列表,差异可以忽略不计,但是我的会分配更多的堆空间。即便如此,Chris的版本对递归函数进行了两次调用,其中只有一次处于尾部位置。Olin Shivers在SRFI 1的评论中指出,以使算法尾部递归的名义使用基于堆的“堆栈”通常是不值得的。阅读“关于递归和迭代/反转的注释”。摘录:对这些算法进行编码的自然而有效的方法是递归的。这将中间临时列表结构转换为中间临时堆栈结构。在基于堆栈的系统中,这可以改进缓存位置并减轻GC系统的负载。不要站在你的头上重复!我同意克里斯杰斯特·杨的说法。不过,学习如何在这两种形式之间进行转换是一种很好的做法,因此我希望尽可能将这两种形式都包括在内(例如,如中所示)。不过,我会更新答案,以表明这不一定会有更高的性能,即使是这样,它也会以一些可读性为代价?应该是,但每个人都回来了。。。除了我的#2答案之外,每个人都是。@GoZoner根据《小阴谋家》(第10页,另见)的说法,“()不是原子。见上文。在方案中,“()不是原子,因此
    (奇数原子?)(())
    应该返回#f。
    (define (odd-atom? obj)
      (and (not (null? obj))
           (or (not (pair? obj))
               (let ((this? (or (null?     (car obj)) 
                                (odd-atom? (car obj))))
                     (rest? (odd-atom? (cdr obj))))
                 (not (eq? this? rest?))))))
    > (odd-atom? '())
    #f
    > (odd-atom? '(()))
    #t
    > (odd-atom? '(() () ()))
    #t
    > (odd-atom? '(() ()))
    #f
    > (odd-atom? '(() (a)))
    #f
    > (odd-atom? '(() (a b)))
    #t
    > (odd-atom? '((a) (a b)))
    #t
    > (odd-atom? '((a b) (a b)))
    #f
    >