我需要在给出时编写一个Scheme函数(union s1 s2)
两套,让我们说
s1 = ((1 3) (5 13) (25 100))
s2 = ((2 4) (17 26) (97 100))
将给出
(union s1 s2) ----> ((1 4) (5 13) (17 100))
如果
s1 = ((1 3) (5 13) (25 110) (199 300))
s2 = ((2 4) (17 26) (97 100) (110 200) (288 500))
然后
(union s1 s2) ----> ((1 4) (5 13) (17 500))
有人可以建议我怎么做吗?我不知道如何开始。
答案 0 :(得分:1)
听起来像个有趣的问题!这听起来像是一个家庭作业问题,所以我会试着指出你的答案,而不是自己写给你。如果我误解了这种情况,我会提前道歉。
首先,我假设各个范围集是有序的,并且是非重叠的。
这个问题非常适合递归模具,具有扭曲性。具体来说,它是“迭代两个复杂数据”的例子,如何设计程序的第17节:
http://www.htdp.org/2003-09-26/Book/curriculum-Z-H-22.html#node_chap_17
更具体地说,你在案例3中,你实际上需要考虑所有可能的组合。
事实上,它甚至比这更糟糕,因为在两组都非空的情况下,你关心的是哪个区间开始较低。
要开始使用,您需要
按照HtDP模板,你应该没问题。不过,这个 是一个棘手的问题。
答案 1 :(得分:1)
我建议
而不是使用2套car
上订购)这样,您总是比较输入(合并)列表的第一个和第二个元素,并且您知道它们是有序的,这极大地简化了您的代码:
执行示例(您的第二个):
(union '((1 3) (5 13) (25 110) (199 300))
'((2 4) (17 26) (97 100) (110 200) (288 500)))
lst: ((1 3) (2 4) (5 13) (17 26) (25 110) (97 100) (110 200) (199 300)
(288 500))
res: ()
lst: ((1 4) (5 13) (17 26) (25 110) (97 100) (110 200) (199 300) (288 500))
res: ()
lst: ((5 13) (17 26) (25 110) (97 100) (110 200) (199 300) (288 500))
res: ((1 4))
lst: ((17 26) (25 110) (97 100) (110 200) (199 300) (288 500))
res: ((5 13) (1 4))
lst: ((17 110) (97 100) (110 200) (199 300) (288 500))
res: ((5 13) (1 4))
lst: ((17 110) (110 200) (199 300) (288 500))
res: ((5 13) (1 4))
lst: ((17 200) (199 300) (288 500))
res: ((5 13) (1 4))
lst: ((17 300) (288 500))
res: ((5 13) (1 4))
lst: ((17 500))
res: ((5 13) (1 4))
lst: ()
res: ((17 500) (5 13) (1 4))
final result: ((1 4) (5 13) (17 500))
我编写了代码,如果你遵循这种方法,它只有11行并且非常简单。
修改强>
既然你要求代码,这是我写的初始版本:
(define (union set1 set2)
(let loop ([lst (sort (append set1 set2) < #:key car)] [res null])
(if (null? lst)
(reverse res)
(let ([e1 (car lst)] [cd (cdr lst)])
(if (null? cd)
(loop null (cons e1 res))
(let ([e2 (car cd)] [e1y (cadr e1)])
(if (> (car e2) e1y)
(loop cd (cons e1 res))
(loop (cons (list (car e1) (max e1y (cadr e2)))
(cdr cd))
res))))))))
或者,如果您希望/需要避免append
和sort
,您可以拥有自己的merge
程序,如下所示:
(define (merge lst1 lst2 cmp key)
(let loop ((lst1 lst1) (lst2 lst2) (res null))
(cond
((and (null? lst1) (null? lst2))
(reverse res))
((and (not (null? lst1))
(or (null? lst2)
(cmp (key lst1) (key lst2))))
(loop (cdr lst1) lst2 (cons (car lst1) res)))
(else
(loop lst1 (cdr lst2) (cons (car lst2) res))))))
并用
替换union
过程的第二行
(let loop ([lst (merge set1 set2 < caar)] [res null])
希望这有帮助。
答案 2 :(得分:1)
这是一个非常简单的问题。每个范围规范都包含间隔列表,按其car
值排序(此外,任何元素的cadr
都小于以下元素的car
)。
您只需从空范围规格开始,即一个空范围的列表:( () )
。
然后,在每一步中,从一个具有最小car
值的列表中取一个头元素(两个中,因为列表是有序的,记得吗?),并将其添加到范围规范中。当两个列表都用完(空)时,你就完成了。
完成同样微不足道。如果您将两个列表保存在一个列表(list s1 s2)
中并编写一个特殊函数get-input
来获取此列表并将其结果作为列表生成next-range
,那么处理输入也会更容易。并且下一个two-lists
(或()
表示两个列表已用完)。
您知道,它是迭代的一般模式的一个实例(通常使用 named-let 或其他尾部递归函数在Scheme中编码,但是有还有一个显式的 do
构造),逐个处理输入列表的元素,将它们与累加器组合在一起。保持累加器的前一部分反转也是一种模式,即。一个拉链。
一个例子(你的第二个):
s1 = ((1 3) (5 13) (25 110) (199 300)) s2 = ((2 4) (17 26) (97 100) (110 200) (288 500)) list-of-ranges last-range two-input-lists () () ( ((1 3) ...) ((2 4) ...) ) () (1 3) ( ((5 13) ...) ((2 4) ...) ) () (1 4) ( ((5 13) ...) ((17 26) ...) ) ((1 4)) (5 13) ( ((25 110) ...) ((17 26) ...) ) ((5 13)(1 4)) (17 26) ( ((25 110) ...) ((97 100) ...) ) ((5 13)(1 4)) (17 110) ( ((199 300)) ((97 100) ...) ) ((5 13)(1 4)) (17 110) ( ((199 300)) ((110 200) ...) ) ((5 13)(1 4)) (17 200) ( ((199 300)) ((288 500)) ) ((5 13)(1 4)) (17 300) ( () ((288 500)) ) ((5 13)(1 4)) (17 500) ( () () ) STOP
答案 3 :(得分:0)
假设没有srfi的r5rs方案,我建议用一个内部递归累加器函数创建一个函数,该函数最初给出s1,s2,intvl-acc ='(),set-acc ='(),最后两个持有临时区间联合和累积联盟列表。
应遵循以下条件: (我会写伪代码,分为三种情况。)
[基本情况]
(and (null? s1) (null? s2))
(if (null? intvl-acc)
reverse(set-acc)
(union-acc '() '() '() (cons intvl-acc set-acc)))
[累积案例]
(not (null? intvl-acc))
(compare (cadr intvl-acc) with caar of each set)
(if s1 is smaller, (union-acc (cdr s1) s2 updated-intvl-acc set-acc))
(if not found, (union-acc s1 s2 '() (cons intvl-acc set-acc)))
[否则:]
else
((compare the caar of s1 s2)
(if s1 is smaller, (union-acc (cdr s1) s2 (car s1) set-acc)
希望它有所帮助。