删除! R5RS的功能

时间:2017-03-14 22:31:52

标签: linked-list scheme filtering mutable r5rs

我试图编写一个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)

2 个答案:

答案 0 :(得分:1)

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

你需要看对子。你想删除3

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

所以当你找到3时,你需要改变保持2的那对的cdr并且将它保持为3 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)等常量数据。结果将是未定义的,否则将发出错误信号。

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

答案 1 :(得分:0)

你需要的只是头哨技术

(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!。最好只维护最后一个cdr单元并更新

(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,使用这种方法你不应该在名称中使用感叹号,因为这将返回新建的列表而不是改变参数的结构