【问题标题】:Insertion sort in place LISP就地插入排序 LISP
【发布时间】:2018-09-15 15:59:17
【问题描述】:

我对正确的 Lisp 还是很陌生,我正在尝试构建一个简单但至少有点高效的插入排序 - 我想在适当的位置切换元素,但仍然能够附加到我的容器然后。我采用了旧的 C++ 实现:

template<typename Iter>
void insertionSort(Iter begin, Iter end){
    for (auto i = begin; i != end; ++i){
        for (auto j = i; j != begin && *(std::prev(j)) > *(j); j--){
            std::iter_swap(j, std::prev(j));
        }
    }
}

并创建了以下代码(考虑到 arefrotatef 具有相当的复杂性),但它似乎对输入没有任何影响(UPD:现在它只是工作不正常),可能是什么我的解决方案有问题吗?我返回是为了测试,是否应该创建一个宏以避免传值?

(defparameter testa (make-array 4 :initial-contents '(2 3 1 5)))
(defun insertion-sort (vect)
    (loop for i from 0 to (1- (length vect)) do
        (loop for j from i downto 0
            until (or (= (1- j) -1) (> (aref vect (1- j)) (aref vect j)))
            do (rotatef (aref vect i) (aref vect (1- j))))
    )
    vect
)
(format t "~a~%" (insertion-sort testa))

UPD:根据@jkiiski 和@RainerJoswig 的cmets 更新了代码,输出仍然错误。

【问题讨论】:

  • 带有两个 FOR 子句的 LOOP 只是一个带有两个变量的循环,而不是像 C++ 版本那样的两个循环。
  • @jkiiski 我已经更新了代码,测试用例的输出还是错误的。
  • 不要使用 EQ 来比较数字。使用 EQL 或 =。
  • (return-from insertion-sort vect) 可以只替换为 vect
  • @RainerJoswig 输出仍然是错误的解决方案

标签: algorithm sorting lisp common-lisp insertion-sort


【解决方案1】:

在你的程序中有几个问题。

首先,排序不起作用,因为该行:

do (rotatef (aref vect i) (aref vect (1- j))))

应该是:

do (rotatef (aref vect j) (aref vect (1- j))))

也就是说,你写的是变量i而不是j

如果你做这个更正,你会发现订单是递减的(我假设你想要一个递增的订单)。这取决于使用until 而不是while

最后,还有多余的代码。更简单高效的版本如下:

(defparameter testa (make-array 4 :initial-contents '(2 3 1 5)))
(defun insertion-sort (vect)
   (loop for i from 1 below (length vect) 
     do (loop for j from i above 0
          while (> (aref vect (1- j)) (aref vect j))
          do (rotatef (aref vect j) (aref vect (1- j)))))
   vect)
(format t "~a~%" (insertion-sort testa))

这与Insertion sort 的维基百科页面中的伪代码平行。

如果你想参数化排序谓词,以及在函数中添加一个可选的基于关键字的“key”参数,这里有一个可能的解决方案:

(defun insertion-sort (vect predicate &key (key #'identity))
  (loop for i from 1 below (length vect) 
        do (loop for j from i above 0
                 while (funcall predicate 
                                (funcall key (aref vect (1- j)))
                                (funcall key (aref vect j)))
                 do (rotatef (aref vect j) (aref vect (1- j)))))
         vect)

CL-USER> (insertion-sort testa #'>)
#(1 2 3 5)
CL-USER> (insertion-sort testa #'<)
#(5 3 2 1)

CL-USER> (defparameter testa (make-array 4 :initial-contents '((c 3) (d 2) (b 1) (a 4))))
TESTA
CL-USER> (insertion-sort testa #'string> :key #'car)
#((A 4) (B 1) (C 3) (D 2))

【讨论】:

  • 谢谢!如何扩展此功能以根据键执行排序?
  • @MikhailKrassavin:您将关键参数放入 arglist。然后你比较(&gt; (funcall key (aref ...)) (funcall key (aref ...)) )
  • @MikhailKrassavin,不客气。我已经更新了答案,以显示 Rainer Joswig 评论的完整解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-11
  • 1970-01-01
  • 2010-10-02
  • 2017-09-04
  • 2020-12-28
  • 1970-01-01
相关资源
最近更新 更多