如何简单明了地编写一个删除函数(来自二叉树)?

时间:2018-06-07 07:11:06

标签: data-structures functional-programming pattern-matching binary-search-tree racket

这是一项任务。但它已经[已经]到期,我想我已经解决了。我是Racket的新手。我觉得我的代码有点单调乏味。有没有更好的方法来改善它?

要求假设提供密钥xk是根节点的值。如果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])]))

1 个答案:

答案 0 :(得分:0)

您应该使用结构谓词,特别是emp?:而不是(equal? lt emp)(这也是错误的,emp应该在parens中),只使用(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-mindelete的递归使用中所显示的那样实现它,它只是效率会低一些... update:将更简单的实现添加到代码中

最小元素将是树中的最左边(保证非空)。只有两种情况需要考虑:树的左子是否为空。您不需要像处理那样明确地处理所有情况。这是不必要的冗长。

另外,在你的描述中(以及在代码中),你已经在地方翻转了分支: left 总是在左边,递归或没有递归。它应该是:

  

如果x&lt; k,在左子树上返回递归 + k + 右子树。如果x> k,在右子树上返回左子树 + k + 递归。如果x = k,(a)如果left为空则返回右子树,(b)如果right为空则返回 left subtree ,或者(c)否则返回左子树 +右最小值+ (右子树 - 最小值)