【问题标题】:Scheme changing tree values改变树值的方案
【发布时间】:2018-10-05 02:33:55
【问题描述】:

我需要实现一个名为 inverse-tree 的过程来接收一棵树 其节点数据值是数字和布尔值,并返回等价​​的 树的节点满足以下条件:

  • 如果原始树的等效节点是一个数字,那么结果树的节点是-1·那个节点值
  • 如果原始树的等效节点是布尔值,则结果树的节点是该节点值的逻辑非

例子:

> (inverse-tree ’())
’()
> (inverse-tree ’(5))
’(-5)
> (inverse-tree ’(0))
’(0)
> (inverse-tree ’(#f))
’(#t)
> (inverse-tree ’(#t))
’(#f)
> (inverse-tree ’(-5 (1 (-2) (3) (#f)) (#t)))
’(5 (-1 (2) (-3) (#t)) (#f))

Scheme 中树(可能为空或不完整)的表示形式如下:每个嵌套层的第一个元素表示子树的根。其余元素是子元素(当然,每个元素都是一棵树)。叶子由只有一个元素(叶子值)的列表表示。一棵完全空的树由空列表表示。

更多信息请访问Scheme altering tree values

【问题讨论】:

  • 您遇到了什么问题?穿过一棵树或其他东西?
  • 我怀疑这是一个练习,你是否了解列表递归(以及 map 的用处),所以你可能想复习一下。
  • 如何遍历树并同时更改值?
  • 如何遍历列表? (定义 (t xs) (cond ((pair?xs) (cons (car xs) (t (cdr xs)))) (else xs)))。如何遍历列表并同时更改值? (define (tc f xs) (cond ((pair?xs) (cons (... (car xs)) (tc f (cdr xs)))) (else xs))) 我怎样才能遍历一棵树并改变同时的价值观? ....
  • 您转换树的方式与map 遍历列表并同时“更改”它的方式几乎相同。也就是说,您创建一个具有相同结构但具有不同值的新树。首先写下树形的可能情况(即空、叶和非空),然后定义每种情况的结果。

标签: tree scheme racket


【解决方案1】:

我认为这应该可行:

  (define inverse-tree
  (lambda (tree)
    (if (null? tree)
        '()
        (if (number? (car tree))
            (cons (* -1 (car tree)) (inverse-tree (cdr tree)))
            (if (boolean? (car tree))
                (cons (not (car tree)) (inverse-tree (cdr tree)))
                (cons (inverse-tree (car tree)) (inverse-tree (cdr tree))))))))

【讨论】:

    【解决方案2】:

    经过大量挖掘和更好地理解语法后,我想出了一个简单的 1 函数解决方案:

    (define (inverse-tree tree)
      (cond ((eq? '() tree) '())
            ((pair? tree) 
             (cons (inverse-tree (car tree))
                        (inverse-tree (cdr tree))))
            (else ((lambda(x) (if (boolean? x) (not x) (- x))) tree))))
    

    【讨论】:

    • 您可以压缩if 并将术语放入cond 中,例如((boolean? tree) (not tree))((number? tree) (- tree)),并可能保留else 用于非数字或布尔值的值。如果您尝试 (inverse-tree '(1 (2) (#f) (symbol))) 会发生什么?在您当前的实现中,猪会飞。如果没问题完全取决于任务,但在工作中我会抛出异常或处理这种情况。
    • @Sylwester 告诉你的是 ((lambda(x) (if (boolean? x) (not x) (- x))) tree) === (if (boolean? tree) (not tree) (- tree))(cond ... (else (if T C A))) === (cond ... (T C) (else A))
    【解决方案3】:

    树结构的解释似乎不起作用。 (1 (-2) (3) 是一个节点,但 1 不是父节点。但是,您似乎可以将整个事物视为二叉树,其中对是节点,空列表是空树,任何其他值都是叶节点。

    抽象看起来像这样:

    (define make-tree cons)
    (define tree-left car)
    (define tree-right cdr)
    (define tree? pair?)
    (define empty-tree '())
    

    您可以像这样映射树的值:

    (define (map-tree proc tree)
      (cond ((eq? empty-tree tree) empty-tree)
            ((tree? tree) 
             (make-tree (map-tree proc (tree-left tree))
                        (map-tree proc (tree-right tree))))
            (else (proc tree))))
    

    例子:

    (map-tree (lambda (v) (+ v 1)) '(1 (2) 3))
    ; ==> (2 (3) 4)
    

    显然,您需要将第一个参数替换为如下所示的过程:

    (inverse #f) ; ==> #t
    (inverse #t) ; ==> #f
    (inverse 5)  ; ==> -5
    ;; optional
    (inverse 'xxx) ; ==> xxx
    

    那么你的程序就很容易了:

    (define (inverse-tree tree)
      (map-tree inverse tree))
    
    (inverse-tree ’(-5 (1 (-2) (3) (#f)) (#t)))
    ; ==> (5 (-1 (2) (-3) (#t)) (#f))
    

    现在,如果您不能使用抽象,则需要使用替换规则。例如。

    (define (tree-inc v)
      (map-tree (lambda (v) (+ v 1)) v))
    
    ; ==
    (define (tree-inc tree)
      (cond ((eq? '() tree) '())
            ...
            (else (+ (car tree) 1))))
    

    你有它。比使用抽象的更难阅读和推理。祝你好运。

    【讨论】:

    • [1 [-2] [3]] 是一棵树。 [1 _ _ ] 是该树的顶部节点。 [1] 是一棵树,也是一个叶节点。 [1 []] 是一棵树,一个有一个空子节点的节点。 [1 [-2] [3 [] [4 [] [5] []] [] [6]] [7]] 是一棵树,一个有 4 个孩子的节点。它的广度优先枚举是[1 -2 3 7 4 6 5]。我认为这没有问题。
    • @WillNess OP 写“每个嵌套级别中的 第一个元素 代表子树的根”。因此[1 [-2] [3]] 是一棵树,其父对象为1。可能没有对任何父节点的引用,除了与cdr 中的节点列表连接时,当前(整个)节点是父节点,但这是隐含的。我的代码仍然有效,因为使用二叉树护目镜以与真实模型相同的方式处理节点。
    • 我不允许使用抽象。如果您可以提供有关最后一个解决方案的更多详细信息并解释我如何在 1 个函数中执行此操作,因为这是请求。
    • @AdamMorad 您只需扩展抽象。查看tree-inc 示例。您会看到正文被 map-tree 的正文替换,对 proc 的调用被参数 (+ v 1) 的正文替换,v 当然是 (car tree)。纯替换。
    • 是否可以按以下方式使用它并使用否定/非关键字?我不允许更改函数定义(define inverse-tree (lambda (tree) (cond ((eq? '() tree) '()) ((pair? tree) (make-tree (inverse-tree (car tree)) (inverse-tree (cdr tree)))) (else (tree)))))
    【解决方案4】:

    写下可能的输入是什么(在树的描述中有三种情况)并为每种情况定义结果。

    这是您需要实现的一般树遍历:

    • 如果树为空:
      • 产生空树
    • 如果树是叶子:
      • 制作倒叶
    • 否则:
      • 反转节点的值
      • 通过将此反转值与反转每个子树的结果相结合来生成一棵新树

    您可能会想在您最喜欢的 Scheme 书籍中阅读有关 map 的内容。

    有可能(但我怀疑这是以后的练习)对此进行概括,以便在树中应用任意函数,就像 map 对列表所做的那样。

    【讨论】:

    • 很遗憾,我不能使用地图。
    • @AdamMorad 当然,您也可以显式递归(但是因为不鼓励抽象而向您的老师“嘘”)。
    • @molbdnilo "BOO" 用于教学递归?我认为 36k 用户,本周前 0.49% 的用户可以避免这种类型的评论。
    • @rsm 通常情况下,列表递归在接近树之前会非常详细地完成,最终会教你如何使用像 mapfold 这样的抽象。 递归很好,教抽象和重用等良好习惯也是如此。强迫坏习惯,比如避免map,即使它是完美的工具并且抽象和重用的一个很好的例证,在我的书中值得“嘘”。
    • @molbdnilo 你是怎么知道这个练习是“强迫坏习惯”?这不是论坛,您的个人意见在这里不合适。再次 - 我希望 36k 用户能更好地了解。 EOT
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-19
    • 2019-03-23
    • 2017-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多