首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >排序算法和命令行接口

排序算法和命令行接口
EN

Code Review用户
提问于 2017-02-15 09:09:43
回答 1查看 178关注 0票数 2

为了好玩,我还实现了一些排序算法(即bubble sortmerge sort),以及命令行接口,并测试了Clojure的功能(我已经对Clojure进行了一段时间的修改,但我仍然是个新手)。

代码看起来不错,但我认为代码的某些部分的样式可能需要改进(主要是merge sort实现,它看起来非常冗长)。除此之外,我还可以使用其他一些改进,比如速度和性能,特别是在更大的列表中。

core.clj:

代码语言:javascript
运行
复制
(ns experiments.core
  (:gen-class)
  (:require [experiments.command-line :as cl]))

(defn bubble-sort [array]
  (loop [ind 0
         sort-arr array
         swaps? 0]
    (if (= ind (dec (count array)))
      (if (not= swaps? 0)
        (bubble-sort sort-arr))
      (if (> (nth sort-arr ind) (nth sort-arr (inc ind)))
        (let
          [temp-arr
            (vec
              (concat
                (subvec sort-arr 0 ind)
                [(nth sort-arr (inc ind))]
                [(nth sort-arr ind)]
                (subvec sort-arr (+ ind 2))))]
          (do
            (println temp-arr)
            (recur (inc ind) temp-arr (inc swaps?))))
        (recur (inc ind) sort-arr swaps?)))))

(defn merge-sort [array]
  (defn split-array [arr]
    (loop [orig arr final []]
      (if (< (count orig) 2)
        (if (= (count orig) 1)
          (conj final orig)
          final)
        (recur
          (subvec orig 2)
          (conj final (subvec orig 0 2))))))
  (defn sort-two [[a b]]
     (loop [arr-a a
            arr-b b
            final []]
       (if
         (or
           (empty? arr-a)
           (empty? arr-b))
         (vec
           (concat
             final
             (if (empty? arr-a) arr-b arr-a)))
         (if (> (first arr-a) (first arr-b))
           (recur
             arr-a
             (vec (rest arr-b))
             (conj final (first arr-b)))
           (recur
             (vec (rest arr-a))
             arr-b
             (conj final (first arr-a)))))))
  (loop
    [sort-arr
      (split-array
        (vec
          (for [a (range (count array))] [(nth array a)])))]
    (if (= (count sort-arr) 1)
      (println (sort-two sort-arr))
      (recur
        (split-array
          (loop [ind 0
                 temp-arr sort-arr]
            (println temp-arr)
            (if (= ind (count temp-arr)) temp-arr
              (recur
                (inc ind)
                (vec
                    (concat
                      (subvec temp-arr 0 ind)
                      [(if (= (count (nth temp-arr ind)) 1)
                         (nth (nth temp-arr ind) 0)
                         (sort-two (nth temp-arr ind)))]
                      (subvec temp-arr (inc ind))))))))))))

(defn gen-random-array [length]
  (loop [arr []]
    (if (= (count arr) length) arr
      (let [rand-val (rand-int length)]
        (if (some #{rand-val} arr)
          (recur arr)
          (recur (conj arr rand-val)))))))

(defn init-args []
  (cl/add-arg "-b" "bubble"
    ["Print the procedure of bubble-sorting,"
     "given an arbitrary amount of arguments."]
    (fn
      ([]
       (bubble-sort
         (gen-random-array 10)))
      ([args]
       (bubble-sort
         (vec
           (for [a (range (count args))]
             (read-string (nth args a))))))))
  (cl/add-arg "-m" "merge"
    ["Print the procedure of merge-sorting,"
     "given an arbitrary amount of arguments."]
    (fn
      ([]
       (merge-sort
         (gen-random-array 10)))
      ([args]
       (merge-sort
         (vec
           (for [a (range (count args))]
             (read-string (nth args a))))))))
  (cl/add-arg "-r" "random"
    ["Generate a random array."]
    (fn
      ([args]
       (println
         (gen-random-array
           (read-string (nth args 0))))))))

(defn -main [& args]
  (init-args)
  (cl/parse-arg (vec args)))

command-line.clj:

代码语言:javascript
运行
复制
(ns experiments.command-line
  (:gen-class)
  (:require [clojure.string :as string]))

(def names (atom [["-h" "help"]]))
(def docs (atom [[""]]))
(def funcs (atom [(fn [] ())]))

(defn add-arg [s-name l-name arg-doc func]
  (swap! names conj [s-name l-name])
  (swap! docs conj arg-doc)
  (swap! funcs conj func))

(defn disp-help []
  (println "\nCommands: ")
  (loop [a 1]
    (if (= a (count @names))
      (print "")
      (do
        (println "  "
          (nth (nth @names a) 0) "\b,"
          (nth (nth @names a) 1) "\b:\n   "
          (string/join "\n    "
            (nth @docs a)))
        (println "")
        (recur (+ a 1))))))

(defn parse-arg [args]
  (let [main-arg (nth args 0)
        other-args (subvec args 1)]
    (loop [a 0]
      (if (= a (count @names))
        (println "No match!")
        (if
          (or
            (= main-arg (nth (nth @names a) 0))
            (= main-arg (nth (nth @names a) 1)))
          (if (= a 0)
            (disp-help)
            ((nth @funcs a) other-args))
          (recur (+ a 1)))))))
EN

回答 1

Code Review用户

发布于 2017-02-16 12:27:20

让我们来对付bubble-sort吧。

if形式

代码语言:javascript
运行
复制
  (if (not= swaps? 0)
    (bubble-sort sort-arr))

..。没有条件失败时发生的情况的表达式,因此返回nil。以上这些需要..。

代码语言:javascript
运行
复制
  (if (not= swaps? 0)
    (bubble-sort sort-arr)
    sort-arr)

这个很管用。

接下来,每次执行交换时,都使用concat重构整个向量。使用assoc交换两个相邻元素的速度更快、更整洁:

代码语言:javascript
运行
复制
(defn bubble-sort [array]
  (loop [ind 0
         sort-arr array
         swaps? 0]
    (if (= ind (dec (count array)))
      (if (zero? swaps?)
        array
        (bubble-sort sort-arr))
      (if (> (nth sort-arr ind) (nth sort-arr (inc ind)))
        (let [temp-arr (assoc sort-arr
                         ind (sort-arr (inc ind))
                         (inc ind) (sort-arr ind))]
          (recur (inc ind) temp-arr (inc swaps?)))
        (recur (inc ind) sort-arr swaps?)))))

我还使用zero?来清理我们以前看过的if

另一项改进是:

bubble-sort函数对每一次通过向量执行递归调用。这将它限制为大约10K长的序列,这取决于JVM的配置方式。否则会导致堆栈溢出。

解决方案是将递归调用(bubble-sort sort-arr)替换为等效的(recur 0 sort-arr 0)。我们还需要将对array的引用替换为对sort-arr的引用,因为array不再在每次传递时都被更新。所以我们替换

代码语言:javascript
运行
复制
(if (zero? swaps?)
  array
  (bubble-sort sort-arr))

和..。

代码语言:javascript
运行
复制
(if (zero? swaps?)
  sort-arr
  (recur 0 sort-arr 0))

这个很管用。试着..。

代码语言:javascript
运行
复制
(-> (range 10000 0 -1) vec bubble-sort)

之前和之后。

一个根本的不匹配是,冒泡排序是通过就地更新来工作的,而clojure的核心数据结构是持久的--您不能改变它们。您从assoc等方面得到的是原始版本的修改版本,它共享它的大部分结构。这带来了很大的性能成本。

因为您没有使用向量的持久性,所以可以使用瞬变。这大大降低了更新的成本- YMMV。为了这样做,

  • 使用transient创建临时版本。
  • assoc替换为assoc!
  • 使用persistent!恢复持久版本。

我们得到..。

代码语言:javascript
运行
复制
(defn bubble-sort [array]
  (loop [ind 0
         sort-arr (transient array)
         swaps? 0]
    (if (= ind (dec (count array)))
      (if (zero? swaps?)
        (persistent! sort-arr)
        (recur 0 sort-arr 0))
      (if (> (nth sort-arr ind) (nth sort-arr (inc ind)))
        (let [temp-arr (assoc! sort-arr
                         ind (sort-arr (inc ind))
                         (inc ind) (sort-arr ind))]
          (recur (inc ind) temp-arr (inc swaps?)))
        (recur (inc ind) sort-arr swaps?)))))

虽然与核心sort相比,运行速度仍然非常慢,但运行速度似乎要快一些。

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/155413

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档