Recursion 如何使用递归合并lisp中按字母顺序排列的两个字符串

Recursion 如何使用递归合并lisp中按字母顺序排列的两个字符串,recursion,lisp,tailrecursion-modulo-cons,Recursion,Lisp,Tailrecursion Modulo Cons,我在学Lisp。我已经实现了一个公共lisp函数,它可以合并两个使用递归按字母顺序排列的字符串。这是我的代码,但有点不对劲,我没弄明白 (defun merge (F L) (if (null F) (if (null L) F ; return f ( L )) ; else return L ;else if (if (null L) F)

我在学Lisp。我已经实现了一个公共lisp函数,它可以合并两个使用递归按字母顺序排列的字符串。这是我的代码,但有点不对劲,我没弄明白

(defun merge (F L)
    (if (null F)
        (if (null L)
            F         ; return f
            ( L ))    ; else return L
        ;else if
        (if (null L)
            F)        ; return F
    ;else if
    (if (string< (substring F 0 1) (substring L 0 1)
        (concat 'string (substring F 0 1) (merge (substring F 1 (length F)) L)))
    ( 
        (concat 'string (substring L 0 1) (merge F (substring L 1 (length L)) ))
    ))))
(取消合并(F L)
(如果(空F)
(如果(空L)
F;返回F
(L);否则返回L
;否则如果
(如果(空L)
F) ;返回F
;否则如果
(如果(字符串<(子字符串F 0 1)(子字符串L 0 1)
(concat'字符串(子字符串f1)(合并(子字符串f1(长度F))L)))
( 
(concat'字符串(子字符串l01)(合并F(子字符串l1(长度L)))
))))
编辑: 我只想合并两个字符串,例如; 输入为字符串a=adf和字符串b=beg 结果或输出应为:;阿布德夫

提前感谢。

这是一种递归方法(根据注释进行修复-其他解决方案也可以获得IF表单)

请注意,这些依赖于将字符串构建到字符列表中,然后对其进行矢量化(字符串是字符的矢量)

你也可以写一个更像C的方法

(defun merge-strings-vector (a b)
  (let ((retstr (make-array (list (+
                                   (length a)
                                   (length b)))
                            :element-type 'character)))
    (labels ((merge-str (a b i)
               (when (and
                    (= (length a)
                       (length b))
                    (/= i (length a)))
                 (setf (aref retstr (* 2 i)) (aref a i))
                 (setf (aref retstr (1+ (* 2 i))) (aref b i))
                 (merge-str a b (1+ i)))))

      (merge-str a b 0)
      retstr)))
请注意,这一个-与其他2个不同-在函数中有副作用。在国际海事组织,这也更难理解

所有3个在SBCL 56上执行的周期数不同;在我的大多数测试中,每项测试似乎都需要6K到11K。我不知道为什么。

这是一种递归方法(根据注释进行修复-其他解决方案也可以获得IF表单)

请注意,这些依赖于将字符串构建到字符列表中,然后对其进行矢量化(字符串是字符的矢量)

你也可以写一个更像C的方法

(defun merge-strings-vector (a b)
  (let ((retstr (make-array (list (+
                                   (length a)
                                   (length b)))
                            :element-type 'character)))
    (labels ((merge-str (a b i)
               (when (and
                    (= (length a)
                       (length b))
                    (/= i (length a)))
                 (setf (aref retstr (* 2 i)) (aref a i))
                 (setf (aref retstr (1+ (* 2 i))) (aref b i))
                 (merge-str a b (1+ i)))))

      (merge-str a b 0)
      retstr)))
请注意,这一个-与其他2个不同-在函数中有副作用。在国际海事组织,这也更难理解


所有3个在SBCL 56上执行的周期数不同;在我的大多数测试中,每项测试似乎都需要6K到11K。我不知道为什么。

根据您的评论判断,您似乎试图将
if
与一系列条件一起使用(就像其他一些语言中的一系列
else if
s)。为此,你可能想要

我用
cond
替换了
if
,并清除了一些其他错误,它成功了

(defun empty (s) (= (length s) 0))

(defun my-merge (F L)
  (cond 
   ((empty F)
    (if (empty L)
      F 
      L)) 
   ((empty L)
    F)
   (t
    (if (string< (subseq F 0 1) (subseq L 0 1))
      (concatenate 'string (subseq F 0 1) (my-merge (subseq F 1 (length F)) L)) 
      (concatenate 'string (subseq L 0 1) (my-merge F (subseq L 1 (length L))))))))

根据您的评论判断,您似乎试图将
if
与一系列条件一起使用(就像一些其他语言中的一系列
else if
s)。为此,你可能想要

我用
cond
替换了
if
,并清除了一些其他错误,它成功了

(defun empty (s) (= (length s) 0))

(defun my-merge (F L)
  (cond 
   ((empty F)
    (if (empty L)
      F 
      L)) 
   ((empty L)
    F)
   (t
    (if (string< (subseq F 0 1) (subseq L 0 1))
      (concatenate 'string (subseq F 0 1) (my-merge (subseq F 1 (length F)) L)) 
      (concatenate 'string (subseq L 0 1) (my-merge F (subseq L 1 (length L))))))))

使用
string使用
string有很多好的答案,那么我为什么还要再添加一个呢?下面的答案可能比这里的其他答案更有效

(defun merge-strings (a b)
  (let* ((lena (length a))
         (lenb (length b))
         (len (+ lena lenb))
         (s (make-string len)))
    (labels
        ((safe-char< (x y)
           (if (and x y) (char< x y)
               (not (null x))))
         (choose-next (x y)
           (let ((ax (when (< x lena) (aref a x)))
                 (by (when (< y lenb) (aref b y)))
                 (xy (+ x y)))
             (cond
               ((= xy len) s)
               ((safe-char< ax by)
                (setf (aref s xy) ax)
                (choose-next (1+ x) y))
               (t
                (setf (aref s xy) by)
                (choose-next x (1+ y)))))))
      (choose-next 0 0))))

(merge-strings "adf" "beg")
(定义合并字符串(a b)
(让*((lena(长度a))
(长b)
(len(+lena lenb))
(使字符串变长)
(标签
((安全字符<(x y)
(如果(和x y)(字符
它的效率更高,特别是在内存分配的意义上——它只分配足够的内存来写入结果字符串,从不强制执行任何操作(从列表到字符串或从数组到字符串等)。它看起来可能不太漂亮,但这是因为它尝试只执行一次每个计算


当然,这并不是编写此函数的最有效方法,但是完全考虑效率的编程不会让您走得更远。

有很多很好的答案,那么我为什么还要再添加一个呢?下面的答案可能比这里的其他答案更有效

(defun merge-strings (a b)
  (let* ((lena (length a))
         (lenb (length b))
         (len (+ lena lenb))
         (s (make-string len)))
    (labels
        ((safe-char< (x y)
           (if (and x y) (char< x y)
               (not (null x))))
         (choose-next (x y)
           (let ((ax (when (< x lena) (aref a x)))
                 (by (when (< y lenb) (aref b y)))
                 (xy (+ x y)))
             (cond
               ((= xy len) s)
               ((safe-char< ax by)
                (setf (aref s xy) ax)
                (choose-next (1+ x) y))
               (t
                (setf (aref s xy) by)
                (choose-next x (1+ y)))))))
      (choose-next 0 0))))

(merge-strings "adf" "beg")
(定义合并字符串(a b)
(让*((lena(长度a))
(长b)
(len(+lena lenb))
(使字符串变长)
(标签
((安全字符<(x y)
(如果(和x y)(字符
它的效率更高,特别是在内存分配的意义上——它只分配足够的内存来写入结果字符串,从不强制执行任何操作(从列表到字符串或从数组到字符串等)。它看起来可能不太漂亮,但这是因为它尝试只执行一次每个计算


当然,这并不是编写此函数的最有效方法,但是完全考虑效率的编程不会让您走得更远。

或者有更好的方法吗?您应该描述您遇到的错误以及不起作用的错误。提供一个包含您所需内容和实际操作的小测试用例也很好。您能正确格式化代码吗?
(L)
将调用
L
,并使用0个参数。第一步,删除所有多余的括号。此外,在左括号后不需要有空格。这使得你的代码很难阅读。如果要返回
L
,请调用
(返回L)
,n
(defun str-merge (F L &aux (s (list nil)) )
  (do ( (p s (cdr p))
        (a (coerce F 'list) (if q a (cdr a)))
        (b (coerce L 'list) (if q (cdr b) b))
        (q nil))
      ( (or (null a) (null b))
          (if a (rplacd p a) (rplacd p b))
          (coerce (cdr s) 'string))
    (setq q (char< (car b) (car a)))
    (if q
      (rplacd p (list (car b)))
      (rplacd p (list (car a))))))
(defun merge-strings (a b)
  (let* ((lena (length a))
         (lenb (length b))
         (len (+ lena lenb))
         (s (make-string len)))
    (labels
        ((safe-char< (x y)
           (if (and x y) (char< x y)
               (not (null x))))
         (choose-next (x y)
           (let ((ax (when (< x lena) (aref a x)))
                 (by (when (< y lenb) (aref b y)))
                 (xy (+ x y)))
             (cond
               ((= xy len) s)
               ((safe-char< ax by)
                (setf (aref s xy) ax)
                (choose-next (1+ x) y))
               (t
                (setf (aref s xy) by)
                (choose-next x (1+ y)))))))
      (choose-next 0 0))))

(merge-strings "adf" "beg")