【问题标题】:delete! function for R5RS删除! R5RS 的功能
【发布时间】:2017-03-14 22:31:51
【问题描述】:

我正在尝试编写一个delete! 函数来改变一个列表并从中删除一个指定的值。这是我目前的代码。

(define (extend! l . xs)
  (if (null? (cdr l))
      (set-cdr! l xs)
      (apply extend! (cdr l) xs)))

(define (delete! lis y)
  (define returnLis '())
  (for-each (lambda(x) (if(not(eq? x y))
                          (extend! returnLis x))) lis)
  returnLis)

我遇到的问题是我试图添加到一个无法在 Scheme 中完成的空列表。

期望的结果:

(删除!'(1 2 3 4 5) 3)
=> (1 2 4 5)

【问题讨论】:

  • 您遇到的问题是...?发布一个示例来演示问题以及您所期望的结果。

标签: linked-list scheme filtering mutable r5rs


【解决方案1】:

您的extend 函数使用实际上会在新对中复制每个元素,但由于初始值为'(),它不能是set-cdr!。改变某些东西的全部意义在于旧变量将继续指向更改的数据,并且复制不会这样做。

您需要查看这些对。你想删除 3

[1,-]->[2,-]->[3,-]->[4,-]->[5,-]->()

所以当你找到 3 时,你需要改变持有 2 的对的 cdr 并将其品脱成持有 3s 的对 cdr,如下所示:

[1,-]->[2,-]->[4,-]->[5,-]->()

然后是这样的:

(define (delete lst e)
  (if (and (not (null? lst)) (not (null? (cdr lst))))
      (if (equal? (cadr lst) e)
          (set-cdr! lst (cddr lst))
          (delete (cdr lst) e))
      'undefined))

(define test (list 1 2 3 4 5)) 
(delete lst 3)
lst ; ==> (1 2 4 5)

请注意,我使用的是list,因为这里不能使用带引号的文字,因为您不能更改像'(1 2 3 4 5) 这样的常量数据。结果将是未定义的,否则将发出错误信号。

如果有问题的元素是第一个,它将不起作用。这是因为变量指向第一对,这只会改变成对的指针,而不是绑定。可以先切换两个并删除第二个,但如果您有一个元素列表,您仍然会被卡住。可变队列的方案实现通常有一个头部,该头部由一个不被视为列表一部分的虚拟元素组成,以删除第一个元素。

【讨论】:

  • 通过突变(同时删除一些元素)构建副本是一种非常有效的技术。
  • @WillNess 是的,但它与 OP 的意图不同,即它“改变一个列表并从中删除一个指定的值”,因为这保证了实际改变参数对。此外,只有未暴露的内部突变不需要感叹号。
  • 啊,是的,完全错过了。 :)
【解决方案2】:

您所需要的只是一个头哨技术

(define (delete! lis y)
  (define returnLis (list 1))
  (for-each (lambda(x) (if(not(eq? x y))
                          (extend! returnLis x))) lis)
  (cdr returnLis))

嗯,不是全部...因为事实上,这是一个二次算法。它从顶部重新搜索returnLis,同时使用extend! 添加每个新元素。最好只维护 last cdr cell 并更新 it

(define (delete! lis y)
  (define returnLis (list 1))
  (define last-cell returnLis)
  (for-each (lambda(x) (cond ((not(eq? x y))
                          ; (extend! last-cell x)
                          (set-cdr! last-cell (list x))
                          (set! last-cell (cdr last-cell)))))
            lis)
  (cdr returnLis))

但是,作为@Sylwester points out,您不应该在名称中使用感叹号,因为这将返回一个新构建的 列表,而不是改变参数的结构。

【讨论】:

    猜你喜欢
    • 2012-12-23
    • 2023-04-01
    • 2021-08-22
    • 2020-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-22
    • 2017-03-18
    相关资源
    最近更新 更多