fork download
  1. ;;; shell-sort.lisp
  2. ;;; Чисто функциональная реализация сортировки Шелла для списков
  3. ;;; (без SET/SETQ/SETF и без индексации), последовательность шагов Р. Седжвика.
  4.  
  5. (defun list-length (l)
  6. (if (null l) 0 (1+ (list-length (cdr l)))))
  7.  
  8. ;; Формула шагов по Р. Седжвику:
  9. ;; для k чётного: g(k) = 1 + 9*2^k - 9*2^(k/2)
  10. ;; для k нечётного: g(k) = 1 + 8*2^k - 6*2^((k+1)/2)
  11. (defun sedgewick-gap (k)
  12. (if (evenp k)
  13. (+ 1 (- (* 9 (expt 2 k)) (* 9 (expt 2 (floor k 2)))))
  14. (+ 1 (- (* 8 (expt 2 k)) (* 6 (expt 2 (floor (+ k 1) 2)))))))
  15.  
  16. ;; Генерация всех шагов < n (в порядке убывания — большие шаги сначала)
  17. (defun sedgewick-gaps (n)
  18. (labels ((gen (k acc)
  19. (let ((g (sedgewick-gap k)))
  20. (if (>= g n) acc (gen (1+ k) (cons g acc))))))
  21. (gen 0 nil)))
  22.  
  23. ;; Создать список из k пустых списков: (nil nil ...)
  24. (defun make-nils (k)
  25. (if (zerop k) nil (cons nil (make-nils (1- k)))))
  26.  
  27. ;; Добавить элемент x в pos-ю подпоследовательность (без мутаций)
  28. (defun add-to-pos (acc pos x)
  29. (if (zerop pos)
  30. (cons (append (car acc) (list x)) (cdr acc))
  31. (cons (car acc) (add-to-pos (cdr acc) (1- pos) x))))
  32.  
  33. ;; Разбить список lst на "gap" подпоследовательностей:
  34. ;; i-я подпоследовательность содержит элементы на позициях i, i+gap, i+2*gap, ...
  35. (defun split-by-gap (lst gap)
  36. (labels ((split-rec (lst pos acc)
  37. (if (null lst)
  38. acc
  39. (split-rec (cdr lst)
  40. (if (= pos (1- gap)) 0 (1+ pos))
  41. (add-to-pos acc pos (car lst))))))
  42. (split-rec lst 0 (make-nils gap))))
  43.  
  44. ;; Вставка элемента в отсортированный список (возврат нового списка)
  45. (defun insert-into-sorted (x sorted)
  46. (if (or (null sorted) (< x (car sorted)))
  47. (cons x sorted)
  48. (cons (car sorted) (insert-into-sorted x (cdr sorted)))))
  49.  
  50. ;; Рекурсивная сортировка вставками
  51. (defun insertion-sort (lst)
  52. (if (null lst) nil
  53. (insert-into-sorted (car lst) (insertion-sort (cdr lst)))))
  54.  
  55. ;; Рекурсивный map
  56. (defun map-rec (f lst)
  57. (if (null lst) nil (cons (funcall f (car lst)) (map-rec f (cdr lst)))))
  58.  
  59. (defun all-empty-p (slist)
  60. (if (null slist) t
  61. (if (null (car slist)) (all-empty-p (cdr slist)) nil)))
  62.  
  63. (defun take-heads-once (slist)
  64. (if (null slist) nil
  65. (let ((h (car slist)))
  66. (if (null h) (take-heads-once (cdr slist))
  67. (cons (car h) (take-heads-once (cdr slist)))))))
  68.  
  69. (defun tails (slist)
  70. (if (null slist) nil
  71. (let ((h (car slist)))
  72. (cons (if (null h) nil (cdr h)) (tails (cdr slist))))))
  73.  
  74. (defun interleave (slist)
  75. (labels ((inter-rec (slist)
  76. (if (all-empty-p slist) nil
  77. (append (take-heads-once slist)
  78. (inter-rec (tails slist))))))
  79. (inter-rec slist)))
  80.  
  81. (defun shell-sort-by-gaps (lst gaps)
  82. (if (null gaps) lst
  83. (let ((g (car gaps)))
  84. (shell-sort-by-gaps
  85. (interleave (map-rec #'insertion-sort (split-by-gap lst g)))
  86. (cdr gaps)))))
  87.  
  88. (defun shell-sort (lst)
  89. "Чисто функциональная сортировка Шелла для списка LIST (по возрастанию)."
  90. (let ((n (list-length lst)))
  91. (shell-sort-by-gaps lst (sedgewick-gaps n))))
  92.  
  93. ;;; -----------------------------
  94. ;;; Примеры использования
  95. ;;; -----------------------------
  96. (defun run-shell-sort-examples ()
  97. "Показать примеры работы shell-sort. Возвращает NIL после вывода."
  98. (format t "~%Shell-sort examples:~%~%")
  99. (format t "1) ~S -> ~S~%" '(3 1 4 1 5 9 2 6 5) (shell-sort '(3 1 4 1 5 9 2 6 5)))
  100. (format t "2) ~S -> ~S~%" '(10 9 8 7 6 5 4 3 2 1) (shell-sort '(10 9 8 7 6 5 4 3 2 1)))
  101. (format t "3) ~S -> ~S~%" '() (shell-sort '()))
  102. (format t "4) ~S -> ~S~%" '(42) (shell-sort '(42)))
  103. (format t "5) ~S -> ~S~%" '(5 3 5 3 2 1 4) (shell-sort '(5 3 5 3 2 1 4)))
  104. nil)
  105.  
Success #stdin #stdout #stderr 0.03s 10204KB
stdin
Standard input is empty
stdout
Standard output is empty
stderr
Warning: reserving address range 0x80000c0000...0x1fffffffffff that contains memory mappings. clisp might crash later!
Memory dump:
  0x8000000000 - 0x80000bffff
  0x14c993000000 - 0x14c9932e4fff
  0x14c993415000 - 0x14c993439fff
  0x14c99343a000 - 0x14c9935acfff
  0x14c9935ad000 - 0x14c9935f5fff
  0x14c9935f6000 - 0x14c9935f8fff
  0x14c9935f9000 - 0x14c9935fbfff
  0x14c9935fc000 - 0x14c9935fffff
  0x14c993600000 - 0x14c993602fff
  0x14c993603000 - 0x14c993801fff
  0x14c993802000 - 0x14c993802fff
  0x14c993803000 - 0x14c993803fff
  0x14c993880000 - 0x14c99388ffff
  0x14c993890000 - 0x14c9938c3fff
  0x14c9938c4000 - 0x14c9939fafff
  0x14c9939fb000 - 0x14c9939fbfff
  0x14c9939fc000 - 0x14c9939fefff
  0x14c9939ff000 - 0x14c9939fffff
  0x14c993a00000 - 0x14c993a03fff
  0x14c993a04000 - 0x14c993c03fff
  0x14c993c04000 - 0x14c993c04fff
  0x14c993c05000 - 0x14c993c05fff
  0x14c993cd8000 - 0x14c993cdbfff
  0x14c993cdc000 - 0x14c993cdcfff
  0x14c993cdd000 - 0x14c993cdefff
  0x14c993cdf000 - 0x14c993cdffff
  0x14c993ce0000 - 0x14c993ce0fff
  0x14c993ce1000 - 0x14c993ce1fff
  0x14c993ce2000 - 0x14c993ceffff
  0x14c993cf0000 - 0x14c993cfdfff
  0x14c993cfe000 - 0x14c993d0afff
  0x14c993d0b000 - 0x14c993d0efff
  0x14c993d0f000 - 0x14c993d0ffff
  0x14c993d10000 - 0x14c993d10fff
  0x14c993d11000 - 0x14c993d16fff
  0x14c993d17000 - 0x14c993d18fff
  0x14c993d19000 - 0x14c993d19fff
  0x14c993d1a000 - 0x14c993d1afff
  0x14c993d1b000 - 0x14c993d1bfff
  0x14c993d1c000 - 0x14c993d49fff
  0x14c993d4a000 - 0x14c993d58fff
  0x14c993d59000 - 0x14c993dfefff
  0x14c993dff000 - 0x14c993e95fff
  0x14c993e96000 - 0x14c993e96fff
  0x14c993e97000 - 0x14c993e97fff
  0x14c993e98000 - 0x14c993eabfff
  0x14c993eac000 - 0x14c993ed3fff
  0x14c993ed4000 - 0x14c993eddfff
  0x14c993ede000 - 0x14c993edffff
  0x14c993ee0000 - 0x14c993ee5fff
  0x14c993ee6000 - 0x14c993ee8fff
  0x14c993eeb000 - 0x14c993eebfff
  0x14c993eec000 - 0x14c993eecfff
  0x14c993eed000 - 0x14c993eedfff
  0x14c993eee000 - 0x14c993eeefff
  0x14c993eef000 - 0x14c993eeffff
  0x14c993ef0000 - 0x14c993ef6fff
  0x14c993ef7000 - 0x14c993ef9fff
  0x14c993efa000 - 0x14c993efafff
  0x14c993efb000 - 0x14c993f1bfff
  0x14c993f1c000 - 0x14c993f23fff
  0x14c993f24000 - 0x14c993f24fff
  0x14c993f25000 - 0x14c993f25fff
  0x14c993f26000 - 0x14c993f26fff
  0x56550761c000 - 0x56550770cfff
  0x56550770d000 - 0x565507816fff
  0x565507817000 - 0x565507876fff
  0x565507878000 - 0x5655078a6fff
  0x5655078a7000 - 0x5655078d7fff
  0x5655078d8000 - 0x5655078dbfff
  0x565508522000 - 0x565508542fff
  0x7fff1cc43000 - 0x7fff1cc63fff
  0x7fff1cda1000 - 0x7fff1cda4fff
  0x7fff1cda5000 - 0x7fff1cda6fff
WARNING: DEFUN/DEFMACRO(LIST-LENGTH): #<PACKAGE COMMON-LISP> is locked
         Ignore the lock and proceed
WARNING: DEFUN/DEFMACRO: redefining function LIST-LENGTH in
         /home/1xi6b6/prog.lisp, was defined in C