Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [Common Lisp] Итеративные->рекурсивные алгоритмы, рекурсивные вызовы 
:(
    Опции темы
Skevalt
Дата 30.11.2006, 19:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 48
Регистрация: 30.11.2006

Репутация: нет
Всего: 3



Товарищи, так как занимаюсь функциональным программирование всего неделю, страшным словом для меня является "рекурсия":) Простые функции еще поддаются пониманию(факториалы, длина списка и т.п.), но вот возникли две задачи, которые я реализовал итеративно и не придумал пока как сделать рекурсивные аналоги предложенных алгоритмов. Уже начинает съезжать крыша...Растолкуйте, пожалуйста, как ЭТО делать:
1.    Дан список, состоящий из подсписков. Построить список, элементами которого являются наибольшие и наименьшие элементы подсписков данного списка, собранные в подсписки.
Реализовал вот так:
Код

(defun minimaxbuild (lst)
   ( prog ()
      ( setq res nil)
      ( do ( (j 0 (+ j 1)) )
           ( (= j (length lst)) res )
           ( setq buf (nth j lst) )
           ( setq max (nth 0 buf) ) 
           ( setq min (nth 0 buf) ) 
           ( do ( (i 1 (+ i 1)) )
                ( (= i (length buf)) (setq res (cons (list max min) res)) )
                ( if (> (nth i buf) max )
                   ( setq max (nth i buf) )
                )
                ( if (< (nth i buf) min )
                   ( setq min (nth i buf) )
                )
           )
      )
      (return (reverse res))
   )
)

(setq lst '((1 2 3 4 5 6)(-1 -2 -3 -4 -5 -6)(0 0 0 0 1 1 1)(1 1 1 1 1 1 1 1)(10 9 8 7 6 5 4)(3.4 1 4.3 -1.3 -2.5 3.33333)))
(minimaxbuild lst)


2.    Даны два списка, состоящие из атомов. Построить список, в котором сначала расположены четные элементы первого списка, а затем нечетные элементы второго:
Реализовал так:
Код

(defun build (sp1 sp2)
   (progn (setq l nil)
      (do ((j 0 (+ j 1)))
           ((= j (length sp1)) l)
           (setq odd (- j (* (/ j 2) 2)))
           (if (not (= odd 0)) (setq l (cons (nth j sp1) l)))
      )
      (do ((j 0 (+ j 1)))
          ((= j (length sp2)) l)
          (setq odd (- j (* (/ j 2) 2)))
          (if (= odd 0) (setq l (cons (nth j sp2) l)))
      )
      (reverse l))
)

(setq sp1 '(1 2 3 4 5 6 7))
(setq sp2 '(9 10 11 12 13 14))
(build sp1 sp2)




 

Это сообщение отредактировал(а) Skevalt - 30.11.2006, 19:03
PM MAIL   Вверх
adejneka
Дата 1.12.2006, 06:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 8.7.2005
Где: Москва, Россия

Репутация: 9
Всего: 11



Во-первых, даже в императивных программах нежелательно постоянно использовать глобальные переменные; имена локальных переменных можно, например, перечислить в скобках после PROG. Во-вторых, LENGTH и NTH вычисляются за время, пропорциональное длине списка и, соответственно, номеру элемента. В результате вся программа работает намного медленнее, чем нужно. Вот несколько вариантов реализации функции, вычисляющей список (max min), на ANSI Common Lisp:

Код

(defun list-max-min (list)
  (cond ((null list)
         '(nil nil))
        ((null (rest list))
         (list (first list) (first list)))
        (t (destructuring-bind (first . rest) list
             (destructuring-bind (max min) (list-max-min rest)
               (list (max max first)
                     (min min first)))))))

(defun list-max-min (list)
  (if (null list)
      '(nil nil)
      (list-max-min-helper (rest list) (first list) (first list))))
(defun list-max-min-helper (list head-max head-min)
  (if (null list)
      (list head-max head-min)
      (let ((first (first list)))
        (list-max-min-helper (rest list) (max head-max first) (min head-min first)))))

(defun list-max-min (list)
  (if (null list)
      '(nil nil)
      (loop for x in list
            maximize x into maximum
            minimize x into minimum
            finally (return (list maximum minimum)))))

(defun list-max-min (list)
  (if (null list)
      nil
      (do* ((rest list (rest rest))
            (x (first rest) (first rest))
            (max x (max max x))
            (min x (min min x)))
           ((null (rest rest))
            (list max min)))))


PM MAIL   Вверх
VH_
Дата 1.12.2006, 10:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 182
Регистрация: 31.10.2006

Репутация: 10
Всего: 11



1. Если предположить, что элементами подсписков (исходного списка) не являются списки (а только атомы), то и в рекурсии нет необходимости (ежели только внутри функций MAX и MIN):
Код

(defun MAXMINLIST (_list)
 (mapcar
 '(lambda (_sublist)
   (list
    (apply 'max _sublist)
    (apply 'min _sublist)))
  _list))

2.  Также рекурсия только внутри "внутренней" функции ODDLIST:
Код

(defun EVENODDLIST (_list1 _list2)
 (append
  (oddlist (cdr _list1))
  (oddlist _list2)))

Код

(defun ODDLIST (_list)
 (cond
  ((null _list) nil)
  ((null (cdr _list)) _list)
  (T (cons (car _list) (ODDLIST (cddr _list))))))

(Хювёнен-Сеппянен "Мир Лиспа" т.1 под именем КАЖДЫЙ-ВТОРОЙ)
PM MAIL   Вверх
adejneka
Дата 1.12.2006, 20:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 105
Регистрация: 8.7.2005
Где: Москва, Россия

Репутация: 9
Всего: 11



В современном стандарте Common Lisp считается, что список, начинающийся с LAMBDA, не является функцией. Соответственно, нужно писать либо (mapcar #'(lambda ...)...), либо (mapcar (lambda ...) ...).

APPLY может работать очень медленно или вообще не работать с длинным списком аргументов. Лучше использовать (reduce #'max _sublist) (заодно, можно указать значение для пустого списка).
PM MAIL   Вверх
VH_
Дата 2.12.2006, 00:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 182
Регистрация: 31.10.2006

Репутация: 10
Всего: 11



IMHO, список, начанающийся с символа LAMBDA, никогда и не являлся функцией (вызовом функции), ибо это есть лямбда-выражение, то есть форма, содержащая изображение вычислений.
Соответственно, при вычислении (mapcar (lambda ...) ...) придется вычислить и выражение (lambda ...) (так как блокирующий вычисление вызов функции QUOTE отсутствует), а это же не вызов функции... и в результате... "Error: Undefined function LAMBDA" ?
Применение лексического замыкания (function (lambda ...)) при отсутствии в замыкаемой функции свободных переменных (не наш ли это случай?) ничем не отличается от применения (quote).
А ежели APPLY (или какая другая функция) может "...вообще не работать...", то IMHO это проблема разработчиков конкретной неработающей среды, а не языка, в котором декларируется, что "...APPLY ... является функцией двух аргументов, из которых первый аргумент представляет собой функцию, которая применяется к элементам списка, составляющим второй аргумент..." и ничего не сказано про длину этого (или какого другого) списка, а что тут скажешь - список он и есть список, а то что же: 10 (100, 1000) - список, а 1001 (10001, 100001) - не список (а что тогда?).
Канечна, после недели изучения такого замечательного LISPа пора уже двигать в сторону Ассемблера (там, говорят, все очень быстро).
PM MAIL   Вверх
linuxfan
Дата 6.12.2006, 14:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 11.10.2006

Репутация: 1
Всего: 1



Рекомендую почитать 3-ю главу замечательной книги Пола Грэхэма «On Lisp»
У меня вторая задача вот так получилась:
Код
(defun build-lists (list1 list2)
  (labels (
    (filter-list (arg predicate)
      (labels (
        (filter-helper (current result)
          (cond
            ((null current) (nreverse result))
            (t (filter-helper
                 (cdr current)
                 (if (funcall predicate (car current))
                   (cons (car current) result)
                   result))))))
        (filter-helper arg nil))))
    (nconc
       (filter-list list1 #'evenp)
       (filter-list list2 #'oddp))))

Но по-любому проще mapcan заюзать smile
PM MAIL   Вверх
_sg
Дата 24.4.2014, 20:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 119
Регистрация: 16.5.2007

Репутация: 2
Всего: 2



как вариант:
Код

(defun edge (w p)
  (mapcar #'(lambda (a) (reduce p a)) w))

(defun max-min-elms (w)
  (values (edge w #'max) (edge w #'min)))

> (max-min-elms '((1 2 3) (4 5 6) (7 8 9)))
(3 6 9)
(1 4 7)

--------------------
vk.com/ansicommonlisp
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума LISP
Void
  • Пожалуйста, создавайте темы с содержательными названиями.
  • Lisp — это целое семейство языков. Всегда указывайте в теме используемый диалект (Common Lisp, Scheme и т.д.).
  • Уважаемые учащиеся, здесь всегда рады помочь Вам, но не делать за Вас вашу работу. У вас гораздо больше шансов получить помощь, если Вы приложите усилия и поделитесь с нами проблемами и результатами. В противном случае добро пожаловать в раздел Центр Помощи.
  • Получив ответ на интересующий Вас вопрос, не забудьте пометить его как решённый.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Void.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | LISP | Следующая тема »


 




[ Время генерации скрипта: 0.1164 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.