【问题标题】:Inserting into a Binary Tree in Scheme在 Scheme 中插入二叉树
【发布时间】:2013-10-23 17:12:03
【问题描述】:

我想知道如何将列表中的元素插入二叉搜索树。我想知道为什么下面的代码不能按我的预期工作。输出是 '((4 1 5 13 6) () ()) 我的下一个问题是对列表中的元素进行排序,但现在我只想插入它们。

我的输出对于我所说的问题是否正确?我的代码如下:

( define ( make-tree value left right ) 
( list value left right ))
( define ( value tree ) ( car tree ))
( define ( left tree ) ( cadr tree ))
( define ( right tree ) ( caddr tree ))

(define (insert-list L T)
 (cond ((null? T) (make-tree L '() '()))
    ((= (car L) (value T)) T)
    ((< (car L) (value T)) (make-tree (value T)
                                      (insert-list (car L) (left T))
                                      (right T)))
    ((> (car L) (value T)) (make-tree (value T)
                                      (left T)
                                      (insert-list (car L) (right T))))))

【问题讨论】:

  • 这个函数怎么调用?你展示了一些输出,但输入是什么?目前尚不清楚您要尝试做什么。由于您将(car L)T 的值进行比较,因此您似乎正在尝试将Lfirst 元素插入T,但是您的递归调用是用(car L) 制作,而不是L。你试图做什么?

标签: recursion scheme binary-tree


【解决方案1】:

这段代码的问题

在编写递归代码时,通常最好考虑一下函数应该将什么作为参数,它应该返回什么,以及基本情况是什么。

(define (insert-list L T)
 (cond
    ((null? T) (make-tree L '() '()))                                     ; case 1
    ((= (car L) (value T)) T)                                             ; case 2
    ((< (car L) (value T)) (make-tree (value T)                           ; case 3
                                      (insert-list (car L) (left T))
                                      (right T)))
    ((> (car L) (value T)) (make-tree (value T)                           ; case 4
                                      (left T)
                                      (insert-list (car L) (right T))))))

根据您的描述,insert-list 应该获取一个元素列表和一棵树,并返回您通过将这些元素插入树中获得的树,一个接一个。这段代码真的做到了吗?有几种情况:

  1. 当树为空时,您确实需要创建一个包含某些元素的新树,但您的第一种情况会创建一个以 整个 列表作为其元素的树,并返回它。这就是为什么你会得到像((4 1 5 13 6) () ()) 这样的结果。你得到了这个基本情况并返回了(make-tree L '() '()))的结果。
  2. 当列表的 first 元素是树的值时,返回树是正确的,因为您不需要执行任何其他操作来插入该 列表的第一个元素。但是你不会对其余元素做任何其他事情。那没有任何好处。如果你有一个像(insert-list '(2 3 4) '(2 () ())) 这样的测试用例,你会看到返回值是(2 () ())
  3. (和 4.)在这些情况下,您会像 (insert-list (car L) (left T)) 这样进行递归调用,但这没有意义,因为 insert-list 的第一个参数应该是元素列表,而您是使用单个元素 (car L) 调用它。不过,您是对的,您认识到需要将(car L) 插入到树的左子树中,并且您正在正确地构造它,只要您调用(insert-element (car L) (left T)) 即可。但是,之后您仍然没有对元素的 rest 执行任何操作。

折叠救援!

如果您尝试获取一个数字列表并将第一个插入到树中以获得新树,然后将第二个数字插入到该树中,依此类推,您正在寻找类似这样的伪代码:

tree = initial-tree
for element in list 
  tree = insert(element,tree)
return tree

这种操作通常在功能上由fold 表示。我在对Flattening a List of Lists 的回答中详细描述了折叠,那里有很多关于它们的信息。这个想法是你想把像

(insert-list '(4 1 5 13 6) '())

进入

(tree-insert (tree-insert (tree-insert (tree-insert (tree-insert '() 4) 1) 5) 13) 6)

这是一个左关联折叠。让我们使用foldl的这个定义:

(define (foldl fn init list)
  (if (null? list)
      init
      (foldl fn (fn init (car list)) (cdr list))))

在这种特殊情况下,您需要实现普通的 tree-insert 函数,该函数接受一棵树,一个元素 a 返回一棵新树,然后您的函数插入 all 中的元素一个列表很简单

(lambda (tree elements)
  (foldl tree-insert tree elements))

例如,

> (foldl tree-insert '() '(3 5 8 1 9))
(3 (1 () ()) (5 () (8 () (9 () ()))))
> (foldl tree-insert '() '(5 8 2 3 1 6 9))
(5 (2 (1 () ()) (3 () ())) (8 (6 () ()) (9 () ())))
> (foldl tree-insert '() '(4 1 5 13 6))             ; the test from the question
(4 (1 () ()) (5 () (13 (6 () ()) ())))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-17
    • 2015-02-13
    • 2019-08-26
    • 1970-01-01
    • 2022-01-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多