fork download
  1. ;;; shell-sort-functional-with-sedgewick.lisp
  2. ;;; Чисто функциональная сортировка Шелла для списков с последовательностью Седжвика.
  3. ;;; Нет setf/setq/loop/nth/length — только car/cdr/cons/recurse.
  4.  
  5. (defun list-length (l)
  6. (if (null l) 0 (1+ (list-length (cdr l)))))
  7.  
  8. (defun sedgewick-sequence (n)
  9. "Генерация последовательности Седжвика (вариант по вашей формуле) для n.
  10. Возвращает список шагов в порядке убывания (большие шаги позже можно обработать по порядку)."
  11. (labels ((sedgewick-iter (k seq)
  12. (let ((next (+ (* 4 (expt 2 k))
  13. (* 3 (expt 2 (1- k)))
  14. 1)))
  15. (if (> next n)
  16. (reverse seq)
  17. (sedgewick-iter (1+ k) (cons next seq))))))
  18. (if (<= n 1)
  19. '(1)
  20. (sedgewick-iter 1 '(1)))))
  21.  
  22. ;;; Создать список из k пустых списков
  23. (defun make-nils (k)
  24. (if (zerop k) nil (cons nil (make-nils (1- k)))))
  25.  
  26. ;;; Добавить x в pos-ю позицию списка списков acc (чисто функционально)
  27. (defun add-to-pos (acc pos x)
  28. (if (zerop pos)
  29. (cons (append (car acc) (list x)) (cdr acc))
  30. (cons (car acc) (add-to-pos (cdr acc) (1- pos) x))))
  31.  
  32. ;;; Развести lst на `step` подпоследовательностей (i-я содержит элементы i, i+step, ...)
  33. (defun split-by-step (lst step)
  34. (labels ((split-rec (lst pos acc)
  35. (if (null lst)
  36. acc
  37. (split-rec (cdr lst)
  38. (if (= pos (1- step)) 0 (1+ pos))
  39. (add-to-pos acc pos (car lst))))))
  40. (split-rec lst 0 (make-nils step))))
  41.  
  42. ;;; Вставка с пользовательским компаратором
  43. (defun insert-into-sorted-cmp (x sorted cmp)
  44. (if (or (null sorted) (funcall cmp x (car sorted)))
  45. (cons x sorted)
  46. (cons (car sorted) (insert-into-sorted-cmp x (cdr sorted) cmp))))
  47.  
  48. (defun insertion-sort-cmp (lst cmp)
  49. (if (null lst) nil
  50. (insert-into-sorted-cmp (car lst) (insertion-sort-cmp (cdr lst) cmp) cmp)))
  51.  
  52. ;;; Рекурсивный map
  53. (defun map-rec (fn lst)
  54. (if (null lst) nil
  55. (cons (funcall fn (car lst)) (map-rec fn (cdr lst)))))
  56.  
  57. ;;; Проверка, что все списки пусты
  58. (defun all-empty-p (slist)
  59. (if (null slist) t
  60. (and (null (car slist)) (all-empty-p (cdr slist)))))
  61.  
  62. ;;; Взять головы всех непустых списков последовательностей (по порядку),
  63. ;;; пропуская пустые
  64. (defun take-heads-once (slist)
  65. (if (null slist) nil
  66. (let ((h (car slist)))
  67. (if (null h)
  68. (take-heads-once (cdr slist))
  69. (cons (car h) (take-heads-once (cdr slist)))))))
  70.  
  71. ;;; Получить хвосты всех подпоследовательностей
  72. (defun tails (slist)
  73. (if (null slist) nil
  74. (let ((h (car slist)))
  75. (cons (if (null h) nil (cdr h)) (tails (cdr slist))))))
  76.  
  77. ;;; Интерлив: собрать список обратно, циклически беря первые элементы из подпоследовательностей
  78. (defun interleave (slist)
  79. (labels ((inter-rec (slist)
  80. (if (all-empty-p slist) nil
  81. (append (take-heads-once slist)
  82. (inter-rec (tails slist))))))
  83. (inter-rec slist)))
  84.  
  85. ;;; Один шаг сортировки: разбить по step, отсортировать каждую подпоследовательность вставками с cmp,
  86. ;;; затем собрать обратно
  87. (defun insertion-sort-step (lst step cmp)
  88. (interleave (map-rec (lambda (sub) (insertion-sort-cmp sub cmp))
  89. (split-by-step lst step))))
  90.  
  91. ;;; Сортировка с заданной последовательностью шагов (список steps),
  92. ;;; обрабатываем шаги от больших к меньшим (если нужно — передайте в нужном порядке)
  93. (defun shell-sort-with-steps (lst steps cmp)
  94. (if (null steps) lst
  95. (shell-sort-with-steps
  96. (insertion-sort-step lst (car steps) cmp)
  97. (cdr steps)
  98. cmp)))
  99.  
  100. (defun shell-sort (lst cmp)
  101. "Сортировка Шелла для списка LIST с компаратором CMP.
  102. CMP — функция двух аргументов (a b) -> T если a должно быть перед b."
  103. (let ((n (list-length lst)))
  104. (if (<= n 1) lst
  105. (let ((steps (sedgewick-sequence n)))
  106. (shell-sort-with-steps lst steps cmp)))))
  107.  
  108. ;;; -----------------------------
  109. ;;; Примеры использования
  110. ;;; -----------------------------
  111.  
  112. (defun show-sedgewick-sequence (n)
  113. (format t "Последовательность Седжвика для n=~S: ~S~%" n (sedgewick-sequence n)))
  114.  
  115. (defun run-shell-sort-examples ()
  116. (format t "~%=== Shell-sort: примеры ===~%~%")
  117. ;; Числа по возрастанию
  118. (let ((numbers '(5 2 8 1 9 4 0 7 3 6)))
  119. (format t "Original numbers: ~S~%" numbers)
  120. (format t "Sorted numbers (asc): ~S~%" (shell-sort numbers #'<)))
  121. ;; Строки по алфавиту
  122. (let ((strings '("banana" "apple" "cherry" "date" "fig")))
  123. (format t "~%Original strings: ~S~%" strings)
  124. (format t "Sorted strings (string<): ~S~%" (shell-sort strings #'string<)))
  125. ;; Числа по убыванию
  126. (let ((numbers2 '(5 2 8 1 9 4)))
  127. (format t "~%Original numbers2: ~S~%" numbers2)
  128. (format t "Sorted numbers2 (desc): ~S~%" (shell-sort numbers2 #'>)))
  129. ;; Сравнение по длине строки
  130. (let ((strings2 '("a" "bb" "ccc" "d" "eeeee")))
  131. (format t "~%Original strings2: ~S~%" strings2)
  132. (format t "Sorted by length: ~S~%" (shell-sort strings2 (lambda (a b) (< (length a) (length b))))))
  133. ;; Пустой и единичный
  134. (format t "~%Empty list -> ~S~%" (shell-sort '() #'<))
  135. (format t "Single -> ~S~%" (shell-sort '(42) #'<))
  136. ;; Показать последовательности Седжвика для разных n
  137. (show-sedgewick-sequence 10)
  138. (show-sedgewick-sequence 50)
  139. (show-sedgewick-sequence 100)
  140. ;; Структуры: точки по координате x
  141. (defstruct point x y)
  142. (let ((points (list (make-point :x 3 :y 5)
  143. (make-point :x 1 :y 2)
  144. (make-point :x 4 :y 7)
  145. (make-point :x 2 :y 1))))
  146. (format t "~%Original points: ~S~%" points)
  147. (format t "Sorted points by x: ~S~%" (shell-sort points (lambda (p1 p2) (< (point-x p1) (point-x p2))))))
  148. (format t "~%=== Конец примеров ===~%")
  149. nil)
  150. (eval-when (:load-toplevel :execute)
  151. (run-shell-sort-examples))
  152.  
Success #stdin #stdout #stderr 0.03s 10432KB
stdin
Standard input is empty
stdout
=== Shell-sort: примеры ===

Original numbers: (5 2 8 1 9 4 0 7 3 6)
Sorted numbers (asc): (0 1 2 3 4 5 6 7 8 9)

Original strings: ("banana" "apple" "cherry" "date" "fig")
Sorted strings (string<): ("apple" "banana" "cherry" "date" "fig")

Original numbers2: (5 2 8 1 9 4)
Sorted numbers2 (desc): (9 8 5 4 2 1)

Original strings2: ("a" "bb" "ccc" "d" "eeeee")
Sorted by length: ("d" "a" "bb" "ccc" "eeeee")

Empty list -> NIL
Single -> (42)
Последовательность Седжвика для n=10: (1)
Последовательность Седжвика для n=50: (1 12 23 45)
Последовательность Седжвика для n=100: (1 12 23 45 89)

Original points: 
(#S(POINT :X 3 :Y 5) #S(POINT :X 1 :Y 2) #S(POINT :X 4 :Y 7)
 #S(POINT :X 2 :Y 1))
Sorted points by x: 
(#S(POINT :X 1 :Y 2) #S(POINT :X 2 :Y 1) #S(POINT :X 3 :Y 5)
 #S(POINT :X 4 :Y 7))

=== Конец примеров ===
stderr
Warning: reserving address range 0x80000c0000...0x1fffffffffff that contains memory mappings. clisp might crash later!
Memory dump:
  0x8000000000 - 0x80000bffff
  0x14ce8bc00000 - 0x14ce8bee4fff
  0x14ce8c015000 - 0x14ce8c039fff
  0x14ce8c03a000 - 0x14ce8c1acfff
  0x14ce8c1ad000 - 0x14ce8c1f5fff
  0x14ce8c1f6000 - 0x14ce8c1f8fff
  0x14ce8c1f9000 - 0x14ce8c1fbfff
  0x14ce8c1fc000 - 0x14ce8c1fffff
  0x14ce8c200000 - 0x14ce8c202fff
  0x14ce8c203000 - 0x14ce8c401fff
  0x14ce8c402000 - 0x14ce8c402fff
  0x14ce8c403000 - 0x14ce8c403fff
  0x14ce8c480000 - 0x14ce8c48ffff
  0x14ce8c490000 - 0x14ce8c4c3fff
  0x14ce8c4c4000 - 0x14ce8c5fafff
  0x14ce8c5fb000 - 0x14ce8c5fbfff
  0x14ce8c5fc000 - 0x14ce8c5fefff
  0x14ce8c5ff000 - 0x14ce8c5fffff
  0x14ce8c600000 - 0x14ce8c603fff
  0x14ce8c604000 - 0x14ce8c803fff
  0x14ce8c804000 - 0x14ce8c804fff
  0x14ce8c805000 - 0x14ce8c805fff
  0x14ce8c815000 - 0x14ce8c818fff
  0x14ce8c819000 - 0x14ce8c819fff
  0x14ce8c81a000 - 0x14ce8c81bfff
  0x14ce8c81c000 - 0x14ce8c81cfff
  0x14ce8c81d000 - 0x14ce8c81dfff
  0x14ce8c81e000 - 0x14ce8c81efff
  0x14ce8c81f000 - 0x14ce8c82cfff
  0x14ce8c82d000 - 0x14ce8c83afff
  0x14ce8c83b000 - 0x14ce8c847fff
  0x14ce8c848000 - 0x14ce8c84bfff
  0x14ce8c84c000 - 0x14ce8c84cfff
  0x14ce8c84d000 - 0x14ce8c84dfff
  0x14ce8c84e000 - 0x14ce8c853fff
  0x14ce8c854000 - 0x14ce8c855fff
  0x14ce8c856000 - 0x14ce8c856fff
  0x14ce8c857000 - 0x14ce8c857fff
  0x14ce8c858000 - 0x14ce8c858fff
  0x14ce8c859000 - 0x14ce8c886fff
  0x14ce8c887000 - 0x14ce8c895fff
  0x14ce8c896000 - 0x14ce8c93bfff
  0x14ce8c93c000 - 0x14ce8c9d2fff
  0x14ce8c9d3000 - 0x14ce8c9d3fff
  0x14ce8c9d4000 - 0x14ce8c9d4fff
  0x14ce8c9d5000 - 0x14ce8c9e8fff
  0x14ce8c9e9000 - 0x14ce8ca10fff
  0x14ce8ca11000 - 0x14ce8ca1afff
  0x14ce8ca1b000 - 0x14ce8ca1cfff
  0x14ce8ca1d000 - 0x14ce8ca22fff
  0x14ce8ca23000 - 0x14ce8ca25fff
  0x14ce8ca28000 - 0x14ce8ca28fff
  0x14ce8ca29000 - 0x14ce8ca29fff
  0x14ce8ca2a000 - 0x14ce8ca2afff
  0x14ce8ca2b000 - 0x14ce8ca2bfff
  0x14ce8ca2c000 - 0x14ce8ca2cfff
  0x14ce8ca2d000 - 0x14ce8ca33fff
  0x14ce8ca34000 - 0x14ce8ca36fff
  0x14ce8ca37000 - 0x14ce8ca37fff
  0x14ce8ca38000 - 0x14ce8ca58fff
  0x14ce8ca59000 - 0x14ce8ca60fff
  0x14ce8ca61000 - 0x14ce8ca61fff
  0x14ce8ca62000 - 0x14ce8ca62fff
  0x14ce8ca63000 - 0x14ce8ca63fff
  0x55b28c977000 - 0x55b28ca67fff
  0x55b28ca68000 - 0x55b28cb71fff
  0x55b28cb72000 - 0x55b28cbd1fff
  0x55b28cbd3000 - 0x55b28cc01fff
  0x55b28cc02000 - 0x55b28cc32fff
  0x55b28cc33000 - 0x55b28cc36fff
  0x55b28d68e000 - 0x55b28d6aefff
  0x7fffd233b000 - 0x7fffd235bfff
  0x7fffd23cb000 - 0x7fffd23cefff
  0x7fffd23cf000 - 0x7fffd23d0fff
WARNING: DEFUN/DEFMACRO(LIST-LENGTH): #<PACKAGE COMMON-LISP> is locked
         Ignore the lock and proceed
WARNING: DEFUN/DEFMACRO: redefining function LIST-LENGTH in
         /home/BR4KHs/prog.lisp, was defined in C