List 使用scheme将元素插入循环列表
我有一个循环列表,例如:#0=(1234.#0) 我想做的是在这个列表中插入一个新元素(x),这样结果就是#0=(x12 3 4.#0#)。我一直在尝试使用此代码(x是循环列表):List 使用scheme将元素插入循环列表,list,insert,scheme,circular-list,List,Insert,Scheme,Circular List,我有一个循环列表,例如:#0=(1234.#0) 我想做的是在这个列表中插入一个新元素(x),这样结果就是#0=(x12 3 4.#0#)。我一直在尝试使用此代码(x是循环列表): 然而,我认为设置cdr!没有像我希望的那样工作。我错过了什么?也许我有点不对劲了?因为您试图将一个元素预先添加到循环列表中,所以需要做两件事: 在包含附加元素的列表前面插入一个新的cons单元格。这很容易,因为您只需执行一个简单的(cons elm x) 您还需要修改循环列表的递归部分以指向新创建的cons单元格,否
然而,我认为设置cdr!没有像我希望的那样工作。我错过了什么?也许我有点不对劲了?因为您试图将一个元素预先添加到循环列表中,所以需要做两件事:
(cons elm x)
eq?
检查来确定,直到它找到一个与列表头部相等的元素
创建一个助手函数来实现这一点,这是insert代码>将如下所示:
(define (find-cdr v lst)
(if (eq? v (cdr lst)) lst
(find-cdr v (cdr lst))))
(define (insert! elm)
(set! x (cons elm x))
(set-cdr! (find-cdr (cdr x) (cdr x)) x))
将元素前置到列表的最简单方法是修改列表的car,并将列表的cdr设置为新的cons,其car是列表的原始第一个元素,cdr是列表的原始尾部:
(define (prepend! x list) ; list = (a . (b ...))
(set-cdr! list (cons (car list) (cdr list))) ; list = (a . (a . (b ...)))
(set-car! list x)) ; list = (x . (a . (b ...)))
现在,这仍然适用于循环列表,因为列表开头的cons单元格(即pair)保持不变,所以“final”cdr仍将指向作为开始的对象。不过,为了测试这一点,我们需要一些函数来创建循环列表并从循环列表中采样,因为它们不包括在语言中(据我所知)
现在,我们可以检查如果在循环列表前加上前缀会发生什么:
(define (insert! elm)
(let ((temp x))
(set-car! x elm)
(set-cdr! x temp)))
(let ((l (make-circular (list 1 2 3))))
(prepend! 'x l)
(display (take 15 l)))
;=> (x 1 2 3 x 1 2 3 x 1 2 3 x 1 2)
我认为这可能比它需要的更复杂。由于尾部已经缠绕,因此更容易修改该cons的车辆,并在该cons之后插入新cons。这使得整个操作的时间保持不变,因为您不需要找到列表的“结尾”。我补充说,这表明了这种方法。谢谢你的回答。然而,我认为我不同意你的情商检查。例如,如果u有一个循环列表,其中有两个相同符号出现,会发生什么情况?当eq检查发现同一符号的第二次出现时,它是否会被错误地告知并认为它已经结束了?例如:#0=(123412.#0#)@Br0dskive不,亚历克西斯的答案不是比较列表中的元素;它实际上是比较列表结构中的实际pair或cons单元格<代码>(cdr lst)
是列表的其余部分,即另一个列表。所以检查(eq?v(cdrlst))
是否为真意味着检查列表v是否与lst的其余列表相同。@Joshua啊,是的,这很有意义。谢谢你的澄清:)谢谢你的回答!我总是发现解决方案比我想象的要简单得多。你说得对,+1!我很少使用可变列表,所以这个解决方案对我来说并不明显,但这肯定比我的方法要好。:)
(define (make-circular list)
(let loop ((tail list))
(cond
((null? (cdr tail))
(set-cdr! tail list)
list)
(else
(loop (cdr tail))))))
(define (take n list)
(if (= n 0)
'()
(cons (car list)
(take (- n 1)
(cdr list)))))
(display (take 10 (make-circular (list 1 2 3))))
;=> (1 2 3 1 2 3 1 2 3 1)
(let ((l (make-circular (list 1 2 3))))
(prepend! 'x l)
(display (take 15 l)))
;=> (x 1 2 3 x 1 2 3 x 1 2 3 x 1 2)