【问题标题】:Binary tree insert node procedure is not working as desired (Scheme)二叉树插入节点过程未按预期工作(方案)
【发布时间】:2019-04-15 13:42:14
【问题描述】:

我实现了一个在二叉树中插入节点的函数。
树节点是(left-node key right-node) 形式的列表。
(insert tree n) 是我的插入节点函数,其中树是二叉搜索树中的树节点列表,我想将键值 n 添加为新节点.

所以,(insert '(((() 4 ()) 5 (() 2 ())) 6 ()) 7) 将输出作为
(((() 4 ()) 5 (() 2 ())) 6 (() 7 ()))

现在,我想做的是这样的:
1。定义一个值列表。 (define (f) (list '1 `2 `3 `4 `5 ))
2。循环遍历列表并在树中逐一输入值,从一棵空树开始。

所以,当我尝试执行第 2 步时,我执行了以下操作:

(define x ()) ;; Tree x is initially empty
(insert x 2)  ;; This prints (() 2 ())
(insert x 1)  ;; This prints (() 1 ()). I want it to be ((() 1 ()) 2 ()).
(insert x 3)  ;; This prints (() 3 ()). I want it to be ((() 1 ()) 2 (() 3 ())).

这就是我卡住的地方。
我在下面提供了我的插入功能。

(define (left tree) (list-ref tree 0))
(define (value tree) (list-ref tree 1))
(define (right tree) (list-ref tree 2))

(define (insert tree n)
  (cond
    [( null? tree ) ( list () n () )]
    [(< n (cadr tree)) (list (insert (car tree) n) (cadr tree) (caddr tree))] 
    [(> n (cadr tree)) (list (car tree) (cadr tree) (insert (caddr tree) n))] 
    [else tree] 
  )
)

有人可以建议我如何实现预期的输出吗?

【问题讨论】:

    标签: scheme lisp binary-tree binary-search-tree


    【解决方案1】:

    您的代码存在三个问题。请注意,在下面我对代码有点粗鲁:我只是在快速编写时直言不讳,我不是试图对你个人粗鲁! p>

    你还没有定义你需要的所有抽象

    您至少需要一个构造树节点的函数、一个测试空树的函数和一个表示空树的对象。这是一组更完整的抽象:

    (define null-tree '())
    
    (define (tree-null? tree)
      (eq? tree null-tree))
    
    (define (make-tree-node left key right)
      (list left key right))
    
    (define (left tree)
      (list-ref tree 0))
    
    (define (value tree)
      (list-ref tree 1))
    
    (define (right tree)
      (list-ref tree 2))
    

    您的 insert 函数不使用抽象

    它不使用您定义的那些,更不用说缺少的那些,导致它是一个难以理解的 1960 年代风格的混乱。这是它的一个版本,它在整个过程中都使用了抽象(这也解决了一些奇怪的间距和悬空括号问题,这些问题无助于阅读您的代码):

    (define (insert tree n)
      (cond
        [(tree-null? tree)
         (make-tree-node null-tree n null-tree)]
        [(< n (value tree))
         (make-tree-node (insert (left tree) n)
                         (value tree)
                         (right tree))]
        [(> n (value tree))
         (make-tree-node (left tree)
                         (value tree)
                         (insert (right tree) n))]
        [else tree]))
    

    你还没理解insert是一个函数

    它需要一棵树并返回一个添加了元素的树,而不是获取一棵树并通过副作用向其中添加元素。 insert 从不修改它的任何参数,而是构造一个合适的新树(如果添加的元素已经存在,则返回现有树)。

    因此,例如,为了添加一系列元素,您需要使用 insert 构造一个添加了这些元素的树序列:

    (define (insert-elements tree elts)
      (if (null? elts)
          tree
          (insert-elements (insert tree (first elts)) (rest elts))))
    

    现在:

    > (insert-elements null-tree '(7 1 2 3 4 7 202 48 20 0))
    '(((() 0 ()) 1 (() 2 (() 3 (() 4 ())))) 7 (((() 20 ()) 48 ()) 202 ()))
    

    为什么要使用抽象

    如果我更改树的抽象:

    (define null-tree '/)
    
    (define (tree-null? tree)
      (eq? tree null-tree))
    
    (define (make-tree-node left key right)
      (vector left key right))
    
    (define (left tree)
      (vector-ref tree 0))
    
    (define (value tree)
      (vector-ref tree 1))
    
    (define (right tree)
      (vector-ref tree 2))
    

    然后我可以在这种新的树类型中使用完全相同的功能

    > (insert-elements null-tree '(7 1 2 3 4 7 202 48 20 0))
    '#(#(#(/ 0 /) 1 #(/ 2 #(/ 3 #(/ 4 /)))) 7 #(#(#(/ 20 /) 48 /) 202 /))
    

    【讨论】:

    • 非常感谢您在如此详细的解释中澄清了一切。现在,我想起来了,我真的误解了插入函数返回一棵新树。另外,感谢您指出使生活更轻松的其他抽象:)。
    • 关于我使用的奇怪缩进,我对 Scheme 很陌生,所以我这样缩进我的代码部分是为了与其他语言有一些相似之处,同时也帮助我弄清楚发生了什么在代码中。
    • @Anjishnu:我认为做 close-paren-on-a-line 的事情很诱人,因为它使它看起来像 C-ish 语言,但这确实是一个错误,因为所有那些悬空的括号只是噪音:当阅读编写良好的 Lisp 代码时,括号应该几乎消失(把它想象成阅读 Python 代码!)
    • 是的,我更习惯 C++ 而不是 Python。但感谢您指出。我将确保我将来编写的 Lisp 代码更少 C-ish :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-02
    • 1970-01-01
    相关资源
    最近更新 更多