删除列表的最后一个元素(方案)
Posted
技术标签:
【中文标题】删除列表的最后一个元素(方案)【英文标题】:removing last element of a list(scheme) 【发布时间】:2011-06-27 18:20:33 【问题描述】:所以我必须删除方案中列表的最后一个元素。
例如,假设我有一个列表(1 2 3 4)
。我需要返回:
(1 2 3)
我的想法:
reverse(list)
car(list)
reverse(list)
scheme(racket) 中有reverse
函数吗?
【问题讨论】:
确实,*** 的一大优点是,一旦发布了问题,就可以在其他帖子中引用和构建它。当您搜索内容时,SO 是 Google 上的热门搜索之一,因此如果将来有人遇到此问题,他们可以从这里学习。 :) 要了解 Racket 是否具有反向功能,请使用 docs.racket-lang.org 查找。 (reverse (cdr (reverse '(1 2 3)))) 在 chez 和球拍中效果很好。在任何情况下,如果您打开解释器(如在终端中),键入一个字母后跟 TAB,您应该访问自动完成建议,这是您自己回答这个问题的好方法。 【参考方案1】:如果后面的元素不是最后一个,我会执行一个递归函数,该函数沿列表向下并附加元素(使用cons
),如果不是,则不附加任何内容。
我已经好几年没做过计划了,所以我能做到的就这么多。
有人可以运行如何实现它(除非这是家庭作业,否则他们可能不应该这样做!)
【讨论】:
-1 每次附加一个列表都是一个 O(n) 操作,这使得你的整个函数 O(n²)。这就是您在使用链表时得到的结果。 追加到列表中不是 O(n)。附加到数组支持的列表是 O(n)。附加到链表(就像在方案中一样)是 O(1)。 @glowcoder:不正确。 预置到一个链表是 O(1)。 追加到一个链表是 O(n) 在被追加的列表上。 (请记住,Scheme 列表是单链表,而不是双链表。) @Chris 不,不是。当您遍历列表时,您已经引用了其中的最后一个元素(尾递归之美),所以它不是 O(n),而是 O(1)。 哦,我明白你在说什么。您在反驳我使用 append 这个词来表示实际的 append 函数,而不是 append 的纯文本概念。在这种情况下,我承认 append 函数会导致函数的顺序膨胀。 :)【参考方案2】:您写道:“倒车,汽车,倒车”。我相信您的意思是写“反向,cdr,反向”。这个解决方案没有任何问题;它在列表的大小上是线性的,就像使用标准列表的任何解决方案一样。
作为代码:
;; all-but-last: return the list, not including the last element
;; list? -> list?
(define (all-but-last l) (reverse (cdr (reverse l))))
如果列表的多次遍历或不必要的另一个列表副本的构造困扰你,你当然可以通过直接写东西来避免它。
鉴于您的几乎解决方案,我将假设这不是家庭作业。
这就是它的样子,在球拍中:
#lang racket
(require rackunit)
;; all-but-last : return the list, except for the last element
;; non-empty-list? -> list?
(define (all-but-last l)
(cond [(empty? l) (error 'all-but-last "empty list")]
[(empty? (rest l)) empty]
[else (cons (first l) (all-but-last (rest l)))]))
(check-equal? (all-but-last '(3 4 5))
'(3 4))
【讨论】:
ps:这个解决方案使用了几个球拍主义:first & rest、error、check-equal? 等。我假设这没问题,因为你的问题被标记为“球拍”。 【参考方案3】:SRFI 1(在 Racket 中使用(require srfi/1)
激活)有一个drop-right
函数:
(drop-right '(1 2 3 4) 1) ; => (1 2 3)
【讨论】:
他可能需要为作业做这件事。 :) 我希望我可以在我的作业中使用它;) 在这个答案的基础上,我相信核心球拍现在有这个,所以不需要require
。【参考方案4】:
有一个reverse
,但使用它不会很有效。我建议使用以下递归函数。
(define (remove-last lst)
(if (null? (cdr lst))
'()
(cons (car lst) (remove-last (cdr lst)))))
(remove-last '(1 2 3 4)) ; returns '(1 2 3)
if
检查它是否在列表的最后一个元素处。
【讨论】:
实际上,reverse
是 O(n),就像你的函数一样。两种方法都可以。
@Chris:它们确实属于同一个复杂度级别,但是这个算法仍然应该快两倍,因为它只遍历列表一次。
仅当您使用“遍历”的非常狭窄的定义时。由于您的函数不是尾递归的,因此从调用堆栈中向上调用可以被视为第二次遍历。
@ChrisJester-Young,我不知道 Racket 是否实现了尾递归模 cons,但这可以解决问题。【参考方案5】:
我会编写一个简单的递归,将典型的“empty?mylist”基本情况更改为“empty?(rest mylist)”,以便在输入列表只有 1 个元素时返回空。
(define (removelast mylist)
(cond
[(empty? (rest mylist)) empty]
[(cons? mylist) (cons (first mylist) (removelast (rest mylist)))]))
(removelast (list 1 2 3 4 5))
顺便说一句,这段代码在 Racket/PLT Scheme 中,它是 Scheme 的一个子集。
【讨论】:
【参考方案6】:我做了一些比:reverse(list), car(list), reverse(list) 更简单的方法来获取最后一个元素,看看:
(define (last-one liste)
(if(null? (cdr liste))
null
(cons (car liste) (last-one (cdr liste)))
)
)
【讨论】:
以上是关于删除列表的最后一个元素(方案)的主要内容,如果未能解决你的问题,请参考以下文章