组合列表没有问题,但按升序排序是我在苦苦挣扎的地方。
(define (combineASC l1 l2)
(cond
((null? l1) l2)
(#t (cons (car l1) (combineASC (cdr l1) l2)))
(sort l2 #'<))) ; I found this part in an online source
这是我得到的输出:
(combineASC '(2 4 6) '(1 4 5))
(2 4 6 1 4 5)
有人对我有任何建议吗?
答案 0 :(得分:4)
所以你要组合两个输入列表,每个列表都按升序排序。你想把它们“编织”成一个,也是按升序排列。
为此,你只需要两个头元素(每个来自每个输入列表)并进行比较;然后你从列表中取出最小的,并进一步结合你剩下的东西 - 使用相同的功能。
不会涉及排序。结果列表将按照定义它的过程的优点进行排序。
此操作通常称为“合并”。它保留了重复。它的重复删除对应物,将两个有序列表合并为一个,称为“联合”。这是因为这些有序(非降序或严格升序)列表可以看作是集合的表示。
需要注意的另一个微妙之处是,当两个头元素相等时该怎么做。我们已经决定保留重复项,是的,但哪两个首先取出?
通常,它是左边的。然后,当这样定义的merge
操作被用作合并排序的一部分时,排序将是 stable (当然,分区也必须正确定义) )。稳定意味着,保留了元素的原始顺序。
例如,如果排序是稳定的,则按对的第一个元素排序时,(3,1) (1,2) (3,3)
保证排序为(1,2) (3,1) (3,3)
而不是(1,2) (3,3) (3,1)
。
因此,按照代码的框架,我们得到
;; combine two non-decreasing lists into one non-decreasing list,
;; preserving the duplicates
(define (combineNONDECR l1 l2)
(cond
((null? l1) l2)
((null? l2) l1)
((<= (car l1) (car l2))
(cons (car l1) (combineNONDECR (cdr l1) l2)))
(t
(cons (car l2) (combineNONDECR l1 (cdr l2))))))
但是如果你真的需要结果是升序顺序,而不是非递减,那么你必须稍微调整一下 - make =
案例分开,并单独处理,以阻止重复进入(每个升序列表中没有重复项,但列表可能包含两个重复项之间的重复项。)< / p>
答案 1 :(得分:1)
因为尾递归:)
(define (merge-sorted . lists)
(define (%merge-sorted head tails)
(cond
((null? tails) head)
((null? (car tails))
(%merge-sorted head (cdr tails)))
(else (let ((sorted
(sort tails
(lambda (a b)
(<= (car a) (car b))))))
(%merge-sorted (cons (caar sorted) head)
(cons (cdar sorted) (cdr sorted)))))))
(reverse (%merge-sorted '() lists)))
(merge-sorted '(1 2 3) '(4 5 6 7 8 9) '(2 4 6) '(1 3 5 7))
我认为这就是威尔所说的:
(define (merge-sorted . lists)
(define (%swap-if-greater lists)
(define (%do-swap head next built tails)
(cond
((null? tails)
(append (reverse built)
(cond
((null? next) (list head))
((> (car head) (car next))
(list next head))
(else (list head next)))))
((> (car head) (car next))
(%do-swap head (car tails)
(cons next built) (cdr tails)))
(else (append (reverse built)
(list head) (list next) tails))))
(%do-swap (car lists)
(if (null? (cdr lists)) '() (cadr lists))
'() (if (null? (cdr lists)) '() (cddr lists))))
(define (%merge-sorted head tails)
(cond
((null? tails) head)
((null? (car tails))
(%merge-sorted head (cdr tails)))
(else (let ((sorted (%swap-if-greater tails)))
(%merge-sorted (cons (caar sorted) head)
(cons (cdar sorted)
(cdr sorted)))))))
(reverse
(%merge-sorted
'() (sort lists (lambda (a b) (<= (car a) (car b)))))))
特别是考虑到方案......对布尔有趣的位置,我不会对这个非常热情。
答案 2 :(得分:0)
(defun merge (l1 l2)
(if (not (and (eql nil l1) (eql l2 nil))
(if (> (car l1) (car l2))
(cons (car l1) (merge (cdr l1) l2))
(cons (car l2) (merge (cdr l2) l1)))
;;;append the not-nil string to the rest.
)
应该有用(你仍然需要完成代码,但想法很清楚)
注意此代码属于common-lisp。
查找merge sort以获取有关该技术的更多信息