删除列表的最后一个元素(方案)

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)))
  )
)

【讨论】:

以上是关于删除列表的最后一个元素(方案)的主要内容,如果未能解决你的问题,请参考以下文章

如何删除一个list中最后一个元素

删除 k 个最后出现的列表元素

如何删除添加到列表中的最后一个元素?

尝试删除最后一个元素时,带有子项的 SwiftUI (2.0) 列表崩溃

如何删除一个list中最后一个元素

不能只删除链接列表中的最后一个元素! (所有其他具有特定值的元素都会被删除)