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