【问题标题】:Using Scheme, how do I merge more than two lists使用Scheme,如何合并两个以上的列表
【发布时间】:2016-03-24 20:10:36
【问题描述】:

我正在尝试在方案中将多个列表合并在一起。我必须确保最终列表已排序,但幸运的是这不会太难,因为必须对给定列表进行排序。另一方面,我还必须检查列表是否已排序。

这是我到目前为止的代码:

/* mergeALot 没有完成;出于某种原因,我在“and”和“else”上出现语法错误。另外,我不知道如何检查第一个元素是否是列表(停止迭代)*/

(define (mergeALot a)
(cond (and
     ordered? (car a)
     ordered? (cadr a))
      (mergeALot(cons
                (merge (car a)(cadr a))
                (cdr (cdr a))))
(else
 (display "Some lists are not ordered"))))


(define (ordered? lst)
  (cond ((null? lst) #t)
        ((eq? (length lst) 1) #t)
  ((> (car (cdr lst)) (car lst))
    (ordered? (cdr lst)))
  (else #f))
 )

(define (merge a b)
  (cond ((null? a) b)
    ((null? b) a)
    ((>= (car a) (car b))
     (cons (car b) (merge a (cdr b))))
    (else
     (cons (car a) (merge (cdr a) b)))))

【问题讨论】:

  • cond 术语周围缺少括号。由于您只有一个结果,您不妨使用if。知道ordered? 不使用像(ordered? (car a)) 这样的括号会计算出一个过程,它是一个真值,因为它不是#f,但您实际上并没有使用该过程。
  • 谢谢。不过,我现在遇到了另一个错误;每次我尝试使用 else 语句时,我都会收到错误“else: not allowed as an expression in:”,即使是我能想到的最基本的 if/else 程序,(define (test a) (if (= 1 2) (#t) (else (#f))))
  • 如果不是功课,(list-sort < (apply append lists)) Like:eval.ironscheme.net/?id=173
  • @i'mpotent if 中没有 else。这只是(if predicate consequent alternative) 例如(if (<= x 3) "You have three or less" "you have more than three")

标签: list merge scheme


【解决方案1】:

这看起来有点像功课,但我会告诉你基本的想法。您可能会得到一个列表列表。由于术语有点失控,我们将列表称为未合并列表。如果未合并列表中只有一个列表,那么您就完成了!但是说有两个。未合并列表中有两个列表。然后,您需要一个使用两个列表并产生合并结果的函数。然后,我必须更新未合并列表。如果我的函数被调用:合并排序,我可能有:

(cons (my-merge (first unmerged-lists) (second unmerged-lists))
      (rest (rest unmerged-lists)))

你会一直这样做,直到 unmerged-lists 只有一个元素,此时你会停止,因为当列表只有一个元素时你不能采取 (rest (rest list)) 。希望你能得到递归!

【讨论】:

  • 是“第一”和“第二”等价于“汽车”和“汽车 cdr”还是我错过了什么
  • 我相信“car”等同于“cons”,“cdr”等同于“rest”我不认为还有其他形式的“first”和“second”,比如,它们代表列表的第一个和第二个元素
  • car 指的是第一个元素,而 cdr 确实与“rest”相同(其中“car cdr”表示“其余的第一个元素”)。你确定这是方案语法吗?我尝试查找“第一”和“第二”,但找不到任何东西。无论如何,感谢您的帮助,它在我的脑海中打开了一堆灯泡。
  • 哦,这可能是因为我习惯了 Racket 方言,从未使用过“实际”方案。我想到了一个有趣的方法,你可以追加所有列表,然后运行排序函数!
【解决方案2】:

进行多路合并有两种基本方法。

第一种方法是依次合并列表:合并前两个列表。然后将第三个列表合并到前两个列表的合并中。然后将第四个列表合并到前三个列表的合并中。以此类推。

第二种方法使用堆,而且速度更快。创建一个堆,每个列表有一个节点,按每个列表中的最小项排序。然后反复从堆中取出最小的项,重新堆。

【讨论】:

  • 谢谢;我尝试实现第一种方式,但最终在“and”上出现语法错误。我也不知道如何检查给定元素是否是列表。你能看一下代码并带领我走得更远吗?当你只用 java 编码时,这些东西真的很令人困惑......
  • 您缺少一些括号,这导致了“and”处的问题。空的反义词?是pair?,可以用来判断一个对象是否是一个列表。我现在没有时间,但下周我会在my blog 进行多路合并。
  • 在写下我的原始答案之后,我实际上想到了第三种方法。所有三种方法的代码都可以在ideone 获得;您可能会喜欢自己弄清楚它是如何工作的。文章将于下周二在my blog 发表;该链接将于下周二生效。
【解决方案3】:

假设您有 3 个排序列表:

unmerged: ((1 2 3) (3 5 6) (1 4 5))

求最小值

找到第一个元素最少的列表。在下文中,我将其称为min-listmin 是该列表的第一个元素:

min-list: (1 2 3)
min: 1

递归调用

min 值改为使用相同unmerged 列表对merge-all 进行递归调用的结果,但您将min-list 替换为(cdr min-list);所有其他列表保持原样。在您的示例中,就好像您调用了:

(cons 1 (merge-all '((2 3) (3 5 6) (1 4 5))))

您计算递归unmerged 列表的方式可能如下:

(map (lambda (u) (if (eq? u min-list) (cdr u) u)) unmerged) 

终止条件

您应该忽略unmerged 列表中的任何空列表,并在所有列表为空时立即停止递归。或者,始终从 unmerged 中删除空列表,并在 unmerged 本身为空时停止。

【讨论】:

    猜你喜欢
    • 2020-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-17
    • 2021-03-05
    • 2021-07-04
    • 2011-04-29
    相关资源
    最近更新 更多