LISP结合两个整数列表并按升序排序?

时间:2012-10-04 18:06:35

标签: lisp scheme racket

组合列表没有问题,但按升序排序是我在苦苦挣扎的地方。

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

有人对我有任何建议吗?

3 个答案:

答案 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))
  • 它更好地扩展:P

我认为这就是威尔所说的:

(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以获取有关该技术的更多信息