实际上,不需要外部定义的循环来判断字符串是否为回文。 [ 备注:嗯,我一开始也是这么想的。但正如@coredump 和@jkiiski 指出的那样,reverse 函数会减慢该过程,因为它会复制整个字符串一次。 ]
用途:
(defun palindromep (s)
(string= s (reverse s)))
[ 这个函数会比你的代码更有效率
如果 s 是回文,则返回 T,否则返回 NIL。](不正确,它只会节省您的写作工作量,但效率低于使用 loop 的过程。)
一个详细的版本是:
(defun palindromep (s)
(let ((result (string= s (reverse s))))
(write (if result
"Is a palindrome"
"Is not a palindrome"))
result))
写出你想要的答案,但返回T 或NIL。
返回T 或NIL 的测试函数的命名约定是以p 结尾的“谓词”。
reverse 函数的性能不如@coredump 建议的 while 循环
这是我的初学者尝试测试速度[不推荐]:
;; Improved loop version by @coredump:
(defun palindromep-loop (string)
(loop with max = (1- (length string))
for i from 0
for j downfrom max
while (< i j)
always (char= (char string i)
(char string j))))
;; the solution with reverse
(defun palindromep (s)
(string= s (reverse s)))
;; the test functions test over and over the same string "abcdefggfedcba"
;; 10000 times over and over again
;; I did the repeats so that the measuring comes at least to the milliseconds
;; range ... (but it was too few repeats still. See below.)
(defun test-palindrome-loop ()
(loop repeat 10000
do (palindromep-loop "abcdefggfedcba")))
(time (test-palindrome-loop))
(defun test-palindrome-p ()
(loop repeat 10000
do (palindromep "abcdefggfedcba")))
(time (test-palindrome-p))
;; run on SBCL
[55]> (time (test-palindrome-loop))
Real time: 0.152438 sec.
Run time: 0.152 sec.
Space: 0 Bytes
NIL
[56]> (time (test-palindrome-p))
Real time: 0.019284 sec.
Run time: 0.02 sec.
Space: 240000 Bytes
NIL
;; note: this is the worst case that the string is a palindrome
;; for `palindrome-p` it would break much earlier when a string is
;; not a palindrome!
这是@coredump 测试功能速度的尝试:
(lisp-implementation-type)
"SBCL"
(lisp-implementation-version)
"1.4.0.75.release.1710-6a36da1"
(machine-type)
"X86-64"
(defun palindromep-loop (string)
(loop with max = (1- (length string))
for i from 0
for j downfrom max
while (< i j)
always (char= (char string i)
(char string j))))
(defun palindromep (s)
(string= s (reverse s)))
(defun test-palindrome-loop (s)
(sb-ext:gc :full t)
(time
(loop repeat 10000000
do (palindromep-loop s))))
(defun test-palindrome-p (s)
(sb-ext:gc :full t)
(time
(loop repeat 10000000
do (palindromep s))))
(defun rand-char ()
(code-char
(+ #.(char-code #\a)
(random #.(- (char-code #\z) (char-code #\a))))))
(defun generate-palindrome (n &optional oddp)
(let ((left (coerce (loop repeat n collect (rand-char)) 'string)))
(concatenate 'string
left
(and oddp (list (rand-char)))
(reverse left))))
(let ((s (generate-palindrome 20)))
(test-palindrome-p s)
(test-palindrome-loop s))
Evaluation took:
4.093 seconds of real time
4.100000 seconds of total run time (4.068000 user, 0.032000 system)
[ Run times consist of 0.124 seconds GC time, and 3.976 seconds non-GC time. ]
100.17% CPU
9,800,692,770 processor cycles
1,919,983,328 bytes consed
Evaluation took:
2.353 seconds of real time
2.352000 seconds of total run time (2.352000 user, 0.000000 system)
99.96% CPU
5,633,385,408 processor cycles
0 bytes consed
我从中学到的:
- 更严格地测试,尽可能多地重复(秒范围)
- 随机生成,然后并行测试
非常感谢@coredump 的好例子!对于@jkiiski 的评论!