【问题标题】:How to reassign value in Dr.Racket如何在 Dr.Racket 中重新分配价值
【发布时间】:2018-04-18 19:41:18
【问题描述】:

我正在尝试在 Scheme-Dr.Racket 中实现二叉树,但插入时遇到了一些问题!功能。

这里是源码

(define (makeTree leftSubTree root rightSubTree)
  (list leftSubTree root rightSubTree))

(define (subTree part tree)
  (if (null? tree)
      '()
      (part tree)))

(define (root tree)
  (subTree cadr tree))

(define (leftSubTree tree)
  (subTree car tree))

(define (rightSubTree tree)
  (subTree caddr tree))

(define (leaf? tree)
  (and (null? (leftSubTree tree))
       (null? (rightSubTree tree))))

; (define tree (makeTree (makeTree '() 1 '()) 2 (makeTree '() 3 '()))) 

(define (member? tree element)
  (if (null? tree)
      #f
      (or (= (root tree) element)
          (member? (leftSubTree tree) element)
          (member? (rightSubTree tree) element))))

(define (insert! tree element)
  (if (null? tree)
      (set! tree (makeTree '() element '()))
      (if (leaf? tree)
          (cond
            ((> (root tree) element) (set! tree (makeTree (makeTree '() element '()) (root tree) '())))
            ((< (root tree) element) (set! tree (makeTree '() (root tree) (makeTree '() element '()))))
            ((= (root tree) element) '()))
          (cond
            ((= (root tree) element) '())
            ((> (root tree) element) (insert! (leftSubTree tree) element))
            (else  (insert! (rightSubTree tree) element))))))

据我所知!函数改变id指向的对象的值或

(set! tree (makeTree '() val '()))

将树的值更改为具有一个节点的树 - val。 有人能解释一下我为什么错了吗?

【问题讨论】:

  • 你为什么要使用set!?这与您使用的函数式编程标签相反。还要注意set!的返回值是未指定的,有些实现返回分配的值,有些什么都不返回。

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


【解决方案1】:

您的insert! 函数只会影响它自己的参数 的绑定,该参数名为tree

当函数返回时,其参数的绑定也随之销毁。

您想影响参数tree 所指的内存对象的结构 的更改。这不是set! 所做的。它只会改变变量绑定的值。

在 Scheme 中有 set-car!set-cdr! 原语,但 Racket 的列表是不可变的。可变列表是用mcons 创建的,而不是cons,也不是list。 Racket 甚至没有set-car! 和朋友,而是将他们称为set-mcar! 等,并且它们不适用于使用list 创建的列表。

您可以使用 define-struct 将树表示从列表切换为结构。

或者,选择适当的 #lang 指令放置在源文件的开头,例如#lang r5rs 所以set-car! 等工作;或使用mcons 创建您的列表,以便您可以使用set-mcar! 等,如果在#lang racket 下工作:

> (define y (mcons 1 (mcons 2 '())))
> y
(mcons 1 (mcons 2 '()))
> (set-mcar! y 11)
> y
(mcons 11 (mcons 2 '()))

【讨论】:

    【解决方案2】:

    怎么了?

    想象一下这个 C 代码:

    void test (int n) {
      n = 6;
    }
    
    int v = 1;
    test(v);
    printf("%d", v)
    

    现在根据您的 Scheme 代码,您希望 6 是打印值,但事实并非如此。 ntest 中的局部变量,与 treeinsert! 中的局部变量相同。当您set! 时,您并没有改变值,而是将标识符应该指向的内容重定向到一个新的(可能是不相关的)值。所有其他指向相同值的绑定仍将指向原始值,因为更改的是绑定n,而不是v

    如何解决

    最好是完全不变异。

    (define (insert tree element)
      (if (tree-empty? tree)
          (make-tree tree-empty element tree-empty)
          (let ((value (tree-value tree))
                (left (tree-left tree))
                (right (tree-right tree)))
            (if (< value element)
                (make-tree (insert left element) value right)
                (make-tree left value (insert right element))))))
    

    您仍然可以像这样替换绑定:

    (set! root (insert root 2))
    

    你可以改变节点。这会让你成为单例树,你需要特别处理一个空的根,因为你不能把 null 变成一个值。解决方案可以是带有空指示的特殊根。

    (define tree-left-place values)
    (define tree-right-place cddr)
    (define tree-value-place cdr)
    (define +root-value (list 'root))
    (define root (make-tree tree-empty %root-value tree-empty))
    (define (insert! tree element)
      (define (insert-helper place)
        (if (tree-empty? (place-value place))
            (set-car! place (make-tree empty-tree element empty-tree))
            (insert! (place-var place) element)))
            
      (let ((value (tree-value tree)))
        (cond ((eq? value +root-value) (set-car! (tree-value-place tree) element))
              ((< element value) (insert-helper (tree-left-place tree)))
              (else (insert-helper (left-right-place tree))))))
    

    【讨论】:

      猜你喜欢
      • 2011-02-05
      • 1970-01-01
      • 2015-09-23
      • 2019-05-20
      • 2020-12-17
      • 2015-02-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多