【问题标题】:Racket Tree Travesal球拍树遍历
【发布时间】:2018-09-07 18:05:28
【问题描述】:

我在使用 Racket 时遇到以下问题。

我正在尝试为通用树实现树前序、后序遍历。

结构体定义为:

(define-struct eempty [])
(define-struct branch [left value right])

我不能使用unless/when 运算符,只能使用ifcond。 我实在想不出解决办法。我查看了维基百科的伪代码,但由于球拍编程范式,它并没有真正的帮助。

(define (inorder tree x)
  (cond [(and (branch? tree) (branch? (branch-left tree))) (inorder (branch-left tree) x)]
        [(and (branch? tree) (branch? (branch-right tree))) (inorder (branch-right tree) x)]

这是我到目前为止所做的,但是在匹配 empty 结构时会出现问题。

更新:

我要做的是按顺序或/和后序显示/打印节点值。

我知道我必须(以某种方式)实现另外 2 个条件:

(and (branch? tree) (empty? (branch-left tree))) do-something x)
(and (branch? tree) (empty? (branch-right tree))) do-something x)

在做某事时我必须做什么?我想我错过了这一点。

有什么帮助吗?

【问题讨论】:

  • 您对树的数据定义是什么?树总是树枝吗?或者它可以是one of 一个空的还是一个分支? (我的意思是在How to Design Programs 的上下文中的数据定义,约翰克莱门茨的回答中提到的教科书。数据定义是设计配方的第一步。)
  • 一棵树是一个分支,它的左右值可以是一个分支,也可以是一个空。示例: (define tree (make-branch (make-branch (make-branch empty 2 empty) 4 (make-branch empty 5 empty)) 10 (make-branch (make-branch empty 12 empty) 15 (make-branch empty 18 空))))

标签: recursion tree racket traversal


【解决方案1】:

我们从我们所拥有的开始:

#lang racket
(define-struct empty [])                     ; no fields
(define-struct branch [left value right])    ; three fields

我们可以尝试制作一些树:

(define t1 (empty))
(define t2 (branch t1 7 t1))

现在我们可以试着玩一下:

> t2
#
> (分支-左 t2)
#
> (左分支 t1)
branch-left:违反合同
  预期:分支?
  给定:#
>(分支?t2)
#t
>(分支?t1)
#F
>(空?t2)
#F
>(空?t1)
#t
>

所以是我们的曲目。 Racket 的 struct 宏定义了各种函数供我们使用——构造函数、访问器、谓词……。

如何打印一个值?说,

(define (display-value v)
  (display #\ )
  (display v))

所以现在我们可以

> (display-value (branch-value t2))
 7

empty 没有 value 字段,只有 branch 有:

(define (display-tree-inorder t)
    (cond
        ((empty? t)
           (display-empty) )                       ; define it later
        ((branch? t)
           (display-branch-inorder                 ; define it later
                           (branch-left t)
                           (branch-value t)
                           (branch-right t)))))

在定义它时,我们遵循类型:我们的树要么是empty,要么是branch。这我们如何用这两个结构定义来定义它们的。

剩下的就是完成display-emptydisplay-branch-inorder 的缺失定义。

但在我们这样做之前,我们还可以有

(define (display-tree-preorder t)
    (cond
        ((empty? t)
           (display-empty) )
        ((branch? t)
           (display-branch-preorder
                           (branch-left t)
                           (branch-value t)
                           (branch-right t)))))

(define (display-tree-postorder t)
    (cond
        ((empty? t)
           (display-empty) )
        ((branch? t)
           (display-branch-postorder
                           (branch-left t)
                           (branch-value t)
                           (branch-right t)))))

那么display-empty 在做什么呢?它什么都不做:

(define (display-empty)
    #f)

那么display-branch-inorder呢?

(define (display-branch-inorder lt val rt)

根据维基百科,我敢肯定,它首先显示它的 left 子树

    (display-tree-inorder .... ) 

然后它会显示它的值

    (display-value .... )

最后显示正确的子树:

    .... )

其他两种变体相同。

在您完成所有这些之后,您会感到有一种通过关注点分离原则进行抽象和概括的冲动。好的。我们的display-tree-inorder 将几件事混为一谈:它根据这个或那个顺序概念遍历一棵树,并对每个节点的值做一些事情。所有这些都可以被抽象出来并作为一个通用过程的参数,比如traverse-tree

所以你看,这很简单:按照类型!一切都会为你准备好。

【讨论】:

  • 非常感谢!这对我很有帮助!
【解决方案2】:

看起来您缺少“空”结构的“条件”分支。您可以参考How To Design Programs 教科书寻求帮助,特别是与混合自引用数据相关的“模板”步骤。

【讨论】:

  • 具体来说,第 4.6 节,Desiging with Itemizations,描述了如何为使用 one of 的数据定义制作 模板。第 9 节,Designing with Self-Referential Data Definitions 有助于将其置于树等自引用数据的上下文中。
  • 这就是我所缺少的。我知道必须有更多的2个条件,即(和(分支?树)(空?(分支左树))和(和(分支?树)(空?(分支左树))。但我没有不明白如果这些条件为真我该怎么办。
  • 啊!不,你陷入了“害怕无效”的陷阱。我猜你有一些编程经验会给你带来问题。您几乎可以肯定只有一个(空的?树)分支。但是,为了更好地回答您的问题,也许您可​​以为您的问题添加更多上下文。具体来说,您想做什么您的订单前或订单后遍历?
  • 我已经用更多信息更新了我的问题。任何帮助表示赞赏!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-24
  • 2021-12-25
  • 1970-01-01
相关资源
最近更新 更多