Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/solr/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
String 不使用Common LISP中的REVERSE函数反转字符串_String_Lisp_Common Lisp_Palindrome - Fatal编程技术网

String 不使用Common LISP中的REVERSE函数反转字符串

String 不使用Common LISP中的REVERSE函数反转字符串,string,lisp,common-lisp,palindrome,String,Lisp,Common Lisp,Palindrome,我正在创建一个程序,可以确定最终项目中的字符串是否为回文。但是,我不允许使用REVERSE功能 (defun palindrome(x) (if (string= x (reverse x)) (format t "~d" ": palindrome" (format t x)) (format t "~d" ": not palindrome" (format t x)))

我正在创建一个程序,可以确定最终项目中的字符串是否为回文。但是,我不允许使用
REVERSE
功能

(defun palindrome(x)
    (if (string= x (reverse x))
        (format t "~d" ": palindrome" (format t x))
        (format t "~d" ": not palindrome" (format t x)))
)
这是我迄今为止对反向函数的尝试

(defun palindrome(x)
    (if (string= x (reverse x))
        (format t "~d" ": palindrome" (format t x))
        (format t "~d" ": not palindrome" (format t x)))
)
我想出的解决这个问题的方法如下。这可能非常复杂

-将字符串拆分为单独的字符,并将它们连接到一个变量中(最后一个字符排在第一位),然后与输入进行比较

-通过递归将每个字符写入另一个变量,从最后一个字符开始,然后与输入进行比较

我只是不知道如何将上述任何一种方法实现到lisp中。

反转字符串 我非常确定在练习中不使用
反向
的限制是为了避免像
(string=s(反向s))
这样的琐碎回答(注意,这种方法做的工作太多,因为您只需要检查一半字符是否相等)和避免生成中间字符串。因此,我猜您可能不会使用
copy seq
make string
,或任何其他分配字符串的标准函数。因此,即使有一种方法可以写一个定制的反面,在你的约束条件下,它也能满足你的需求,这可能会违背练习的精神

例如,这里有一个
my reverse
函数,它依赖于和。同样,我不认为你应该用它来解决这个问题,这只是为了说明如何做到:

(defun my-reverse (s)
  (do* ((n (length s))
        (z (make-string n))
        (i 0 (1+ i))
        (j (1- n) (1- j)))
       ((>= i n) z)
    (setf (char z i) (char s j))))
基本上,
i
从零开始增加,
j
从字符串中的最后一个位置开始减少,循环的每次迭代都将结果字符串中
i
位置的字符设置为原始字符串中
j
位置的字符

回文检查 您可以通过查看字符串来编写回文检查,而无需创建新字符串并将其反转。例如,您可以调整上面的循环,以便它检查回文,而不是创建新字符串

另一种可能的实现方法是遵循回文的递归定义:

  0: (PALINDROMEP "ABCDEF")
    1: (BOUNDED-PALINDROME-P "ABCDEF" 0 5)
    1: BOUNDED-PALINDROME-P returned NIL
  0: PALINDROMEP returned NIL
  • 空字符串是回文
  • 一个字符的字符串是回文
  • 如果S是回文,C是字符,那么CSC是回文
根据这个定义,可以定义一个相应的递归过程来检查回文。但是请注意,您不需要构建中间字符串。您只需要比较字符串中不同索引处的字符

例如,我有以下跟踪:

空字符串:

  0: (PALINDROMEP "")
    1: (BOUNDED-PALINDROME-P "" 0 -1)
    1: BOUNDED-PALINDROME-P returned T
  0: PALINDROMEP returned T
单字母字符串:

  0: (PALINDROMEP "A")
    1: (BOUNDED-PALINDROME-P "A" 0 0)
    1: BOUNDED-PALINDROME-P returned T
  0: PALINDROMEP returned T
长度超过1的回文:

  0: (PALINDROMEP "ABCBA")
    1: (BOUNDED-PALINDROME-P "ABCBA" 0 4)
      2: (BOUNDED-PALINDROME-P "ABCBA" 1 3)
        3: (BOUNDED-PALINDROME-P "ABCBA" 2 2)
        3: BOUNDED-PALINDROME-P returned T
      2: BOUNDED-PALINDROME-P returned T
    1: BOUNDED-PALINDROME-P returned T
  0: PALINDROMEP returned T
非回文:

  0: (PALINDROMEP "ABCDEF")
    1: (BOUNDED-PALINDROME-P "ABCDEF" 0 5)
    1: BOUNDED-PALINDROME-P returned NIL
  0: PALINDROMEP returned NIL
另一个有一些共同字母的失败测试:

  0: (PALINDROMEP "ABCDEFBA")
    1: (BOUNDED-PALINDROME-P "ABCDEFBA" 0 7)
      2: (BOUNDED-PALINDROME-P "ABCDEFBA" 1 6)
        3: (BOUNDED-PALINDROME-P "ABCDEFBA" 2 5)
        3: BOUNDED-PALINDROME-P returned NIL
      2: BOUNDED-PALINDROME-P returned NIL
    1: BOUNDED-PALINDROME-P returned NIL
  0: PALINDROMEP returned NIL

我想说,最简单的方法是简单的循环,如下所示:

(defun palindrome? (s)
  (not
   (loop for c1 across s
         for end from (1- (length s)) downto (/ (length s) 2)
         when (char/= c1 (char s end))
           do (return t))))
如果在每个步骤上缩小边界,则从结尾开始,检查字符是否相等,并在遇到不相等的字符时立即停止(迭代部分确保循环在到达字符串中间时结束,这意味着它是回文)

更新

正如@coredump所建议的,这一点可以通过以下方式简化:

(defun palindrome? (s)
  (loop for c1 across s
        for end from (1- (length s)) downto (/ (length s) 2)
        always (char= c1 (char s end))))
通过递归 查找第一个和最后一个元素 字符串的字符列表,在第一次不合格之前它们是否相等 发生并返回
nil
。 测试的第一个和最后一个元素从列表中切掉 通过
cdr
butlast

;; helper function working with list of chars
(defun %palindromep (chars)
  (cond ((null chars) t)
        ((char= (first chars) (car (last chars))) 
         (%palindromep (butlast (cdr chars))))
        (t nil)))

;; function working with strings
(defun palindomep (s)
  (%palindromep (coerce s 'list)))

这个答案特别关注列表(不是向量)的递归回文检查,作为对用户答案的评论的后续。有一种递归方法可以检查回文列表,它不分配新列表,只在O(n)时间内迭代给定列表,即在线性时间内,而不是二次时间内

为了解释这种方法,让我定义一个辅助函数,
映射对立
,它是一个高级函数,将函数映射到列表两端的值。例如,
(映射相反的f'(abc))
对以下参数对调用
f
(caa)
(bb)
(acc)
(按该顺序)。然后,
palindrome
check函数将只是
映射对立面的一个应用程序,带有一个闭包(提前退出)

为了使
映射对立面
对回文检查有用(可能还有其他功能),它还跟踪列表中每个元素的当前索引。
映射对向
调用的函数应接受两个值
x
y
,以及两个索引
x-index
y-index

映射对立 让我们定义一个辅助函数并跟踪它,以及
映射对立面%

(defun dbg (&rest args)
  (declare (ignore args)))

(trace map-opposites% dbg)
使用此输入调用主函数:

(map-opposites 'dbg '(a b c d e))
提供以下跟踪(为清晰起见,已编辑包前缀):

主要有两个区域:

  • 首先,函数递归到最终的空列表,同时计算列表的大小;请注意,整个原始列表作为第三个参数未经修改地传递

  • 当展开堆栈时,整个列表将被第二次遍历(请参见第二次返回值),而调用堆栈将向上移动。事实上,有人可能会认为调用堆栈扮演着列表副本的角色

  • 更准确地说,请注意:

  • 在递归的底部,函数返回列表的大小以及整个列表。当堆栈向上展开时,整个列表将向下访问

  • 在递归的中间级别,我们有当前值
    h1
    (向下递归时获得的值),第二个值
    h2
    通过迭代整个列表(c)获得
    0: (MAP-OPPOSITES% DBG (A B C D E) (A B C D E) 0)
      1: (MAP-OPPOSITES% DBG (B C D E) (A B C D E) 1)
        2: (MAP-OPPOSITES% DBG (C D E) (A B C D E) 2)
          3: (MAP-OPPOSITES% DBG (D E) (A B C D E) 3)
            4: (MAP-OPPOSITES% DBG (E) (A B C D E) 4)
              5: (MAP-OPPOSITES% DBG NIL (A B C D E) 5)
              5: MAP-OPPOSITES% returned 0 (A B C D E)
              5: (DBG E A 4 0)
              5: DBG returned NIL
            4: MAP-OPPOSITES% returned 1 (B C D E)
            4: (DBG D B 3 1)
            4: DBG returned NIL
          3: MAP-OPPOSITES% returned 2 (C D E)
          3: (DBG C C 2 2)
          3: DBG returned NIL
        2: MAP-OPPOSITES% returned 3 (D E)
        2: (DBG B D 1 3)
        2: DBG returned NIL
      1: MAP-OPPOSITES% returned 4 (E)
      1: (DBG A E 0 4)
      1: DBG returned NIL
    0: MAP-OPPOSITES% returned 5 NIL
    
    (defun palindrome (list)
      (prog1 t
        (map-opposites (lambda (x y ix iy)
                         (when (<= ix iy)
                           (return-from palindrome t))
                         (unless (eql x y)
                           (return-from palindrome nil)))
                       list)))
    
    (defun map-opposite-indices% (fun list i1)
      (if list
          (let ((i2 (map-opposite-indices% fun (rest list) (1+ i1))))
            (funcall fun i1 i2)
            (1+ i2))
          0))
    
    (defun map-opposite-indices (fun list)
      (map-opposite-indices% fun list 0))
    
    (defun dbg (&rest args)
      (print args))
    
    (map-opposite-indices 'dbg '(a b c d e))
    
    (4 0) 
    (3 1) 
    (2 2) 
    (1 3) 
    (0 4) 
    
    (defun map-opposites% (fun l1 whole)
      (if l1
          (destructuring-bind (h1 . t1) l1
            (let ((l2 (map-opposites% fun t1 whole)))
              (when l2
                (destructuring-bind (h2 . t2) l2
                  ;; in the base case l2 is the whole list (a b c d e)
                  ;; then one level up in the recursion l2 is bound to
                  ;; (b c d e); one level up it is (c d e), 
                  ;; then (d e), etc.
                  ;; At the same levels of recursion, l1 is bound 
                  ;; respectively to (), then (e), then (d e), 
                  ;; then (c d e), etc.
                  (prog1 t2 
                    (funcall fun h1 h2))))))
          whole))
    
    (defun map-opposites (fun list)
      (map-opposites% fun list list))
    
    (defun dbg (&rest args)
      (print args))
    
    (map-opposites 'dbg '(a b c d e))
    
    (E A) 
    (D B) 
    (C C) 
    (B D) 
    (A E)