data-structures - 如何简单明了地编写删除函数(从二叉树)?
问题描述
这是一个任务。但它[已经]到期了,我想我解决了。我是新来的球拍。我觉得我的代码有点乏味。有没有更好的改进方法?
该要求假设给出一个 key x
,并且k
是根节点的值。如果,则返回左子树 + + 右子x < k
树上的递归。k
如果,则返回右子树 + + 左子x > k
树上的递归。k
如果x=k
,(a)如果左为空则返回右子树,(b)如果右为空则返回左子树,否则(c) 返回右最小值+左子树+(右子树-最小值):
(define (delete x tree)
(match tree
[(emp) (emp)]
[(node k lt rt)
(cond
[(< x k) (node k (delete x lt) rt)]
[(> x k) (node k lt (delete x rt))]
[else
(cond
[(equal? lt emp) rt]
[(equal? rt emp) lt]
[else
(define (get-min tree)
(match tree
[(emp) (emp)]
[(node k (emp) (emp)) k]
[(node k lt (emp)) (get-min lt)]
[(node k (emp) rt) k]
[(node k lt rt) (get-min lt)]))
(node (get-min rt) lt (delete (get-min rt) rt))])])]))
以下是给定的树结构。我们不应该修改它。
; The empty tree is represented by an "emp" record of 0 fields.
(struct emp () #:transparent)
; A node is represented by a "node" record of key, left child, right child.
(struct node (key left right) #:transparent)
; BST insert.
(define (insert x tree)
(match tree
[(emp) (node x (emp) (emp))]
[(node k lt rt)
(cond
[(< x k) (node k (insert x lt) rt)]
[(< k x) (node k lt (insert x rt))]
[else tree])]))
解决方案
您应该使用结构谓词,特别是emp?
: 而不是(equal? lt emp)
(这也是错误的,emp
应该在括号中),使用 just (emp? lt)
。
当一个函数太长时,这是一个明确的迹象,它应该被分解成更小的函数。
最后,树的最小元素的删除和报告应该在一个函数中完成,一次遍历树。delete
太宽泛了,它正在搜索给定的元素;但是在这里我们已经知道元素将在最左边的位置:
(define (delete x tree)
(define (join lt rt) ; all values that are in lt
(cond ; are less than those in rt
[(emp? lt) rt]
[(emp? rt) lt]
[else (call-with-values ; use rt's minimum value
(lambda () (min-elem rt)) ; as the new top node's
(lambda (k tree)
(node k lt tree) ))]))
(define (min-elem tree) ; tree is guaranteed to be non-empty
; a less efficient mock-up; better if done with one traversal
(let ([minval (get-min tree)])
(values minval (delete minval tree))))
(define (get-min tree) ; leftmost value in a non-empty tree
(match tree
[(node k (emp) _) k]
[(node _ lt _) (get-min lt)]))
(match tree
[(emp) (emp)]
[(node k lt rt)
(cond
[(< x k) (node k (delete x lt) rt)]
[(> x k) (node k lt (delete x rt))]
[else (join lt rt)])])) ; removing the top
min-elem
返回最小元素和删除后剩余的有效树 是有责任的 (请参阅和和递归使用,那样效率会降低......更新:在代码中添加了更简单的实现)。values
call-with-values
get-min
delete
最小元素将是树中最左边的元素(保证非空)。只有两种情况需要考虑:树的左孩子是否为空。你不需要像你一样明确地处理所有的情况。它是不必要的冗长。
此外,在您的描述(和代码中)中,您已经在某些地方翻转了分支:left总是在左边,递归或不递归。它应该是:
如果 x < k,则返回左子树+ k +右子树上的递归。如果 x > k,则返回左子树+ k +右子树上的递归。如果 x=k,(a)如果左为空则返回右子树,(b)如果右为空则返回左子树,或者(c)否则返回左子树+ 右最小值 + (右子树 - 最小值)。
推荐阅读
- python - 计算图表中节点的所有可能路径
- c++ - 无法理解 C++ 代码注释中的反斜杠
- html - 如何将 adsense amphtml 广告添加到网页?
- dynamics-crm - Azure 数据工厂 - GUID 查找
- javascript - 在 foreach(模型中的项目)循环中获取特定的表行数据
- salesforce - Invocablemethod Apex 类汇总多个货币字段
- spring-boot - 在骆驼处理器中从 application.yml 注入
- android - 资产链接域与主机
- r - 合并重复的列,其中行大于其他列
- c# - 查询 DbSet (C#) 时要求 Skip 和 Take