![]() |
|
Модераторы: Poseidon |
![]()
|
|
| Mogaba |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 2 Регистрация: 14.10.2007 Репутация: нет Всего: нет |
Я в прологе не очень разбираюсь, поэтому сильно не бейте:)
Нужно решить на TurboProlog такую задачу: Дано N чисел. Определить, сколько из них отлично от последнего числа. И объясните решение, если можно. |
|||
|
||||
| Shaggie |
|
||||||||||||||||||||||||
![]() Опытный ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 570 Регистрация: 21.12.2006 Где: outer space Репутация: нет Всего: 72 |
Чует сердце, что с ответом я немножко припозднился... Но вдруг кому ещё поможет. И обещаю разъяснить! Задачка, кстати, зело интересная. Прошу расценивать это скорее как познавательную статью, нежели запоздалый ответ на вопрос.
Итак, нам нужен предикат вроде diffLast(List, Diffs), который находил бы последний элемент списка и сравнивал все элементы списка с найденным. Итого задачу можно разбить на две части: вызов предиката last(List, Last), находящий последний элемент в списке, и diff(List, Last, Diffs), который сравнит каждый элемент списка с заранне найденным последним элементом. Записывается это так:
Теперь надо описать предикат для нахождения последнего элемента в списке. Для начала абстрагируемся от уже написанного предиката last(List, Last) и попробуем написать новый, совершенно с нуля, назовём его last_(). Что передаётся в last_() ? Во-первых, список, последний элемент которого мы ищем: last_(List). Как найти последний элемент? Очевидно, требуется перебрать все элементы, пока список не кончится, и последний элемент окажется искомым. Значит, голову списка надо каждый раз передавать заново: last(List, Head). Но как нам вернуть найденый последний элемент? Значит необходим третий аргумент, который окажется вычислен только в момент полной раскрутки списка и будет возвращён без имзменений: last_(List, Head, Last). Теперь мы можем сформулировать условие, при котором предикат last_() будет возвращать истинное значение. Представим, что мы раскрутили весь список, рекурсивно передавая его головной элемент вторым аргументом, и достигли конца списка. Теперь переданный аргумент автоматически оказывается последним, и его значение должно совпадать со значением третьего аргумента (того, который теперь будет возвращён наверх. Это напоминает поплавок, который выталкивается на поверхность озера
Восклицательный знак даёт команду виртуальной машине отсечь все варианты, достигнутые ранее, чтобы более к ним не возвращаться. Это повышает эффективность алгоритма. Рекомендую обратиться к специализированной литературе по языку. Если не можете рассказать своими словами, что и зачем происходит в этот момент, то запись можно сократить до
Теперь формулируем условие, при котором список не пуст. Что нужно сделать? Хм... изъять голову списка и рекурсивно вызвать предикат ещё раз:
Прочерк на месте второго аргумента означает, что нас абсолютно не волнует, какое именно значение окажется при вызове этого предиката. И в самом деле - если этот элемент не последний в списке (а он не последний, так как у списка есть хвост, даже если в нём нет ни одного элемента), то какое нам до него дело? И теперь осталось только вызвать его из уже придуманного нами предиката last(List, Last), передав соответствующие параметры:
Обобщим опыт:
Обратите внимание - предикат last_([], Last, Last) идёт первым. Pattern Matching с этим предикатом нас интересует больше, чем со следующим. Теперь дело за предикатом diff( List, Last, Diffs). Задача: сформулировать безусловно истинный предикат, не требующий никаких лишних телодвижений. Возможно ли это? Да! При условии, что в списке List остаётся только один последний элемент, такой же как и Last, счётчик отличных элементов будет равным нулю:
Характерное условие - сначала нам нужно раскрутить список до конца, чтобы переменная Diffs оказалась инициализирована нулём. Теперь при возвратах можно будет сравнивать голову списка с элементом Last, и при их неравенстве инкрементировать счётчик Diffs. Только при возвратах! Нельзя инкрементировать счётчик, если переменная не инициализирована, это приведёт к исключению. Итак, какие есть два возможных варианта паттерн матчинга? Первый - это если голова списка эквивалентна искомому элементу. Тогда инкремента не происходит. Второй - это если голова списка не эквивалентна искомому элементу. В таком случае перемнная Diffs увеличивается на единицу.
Порядок матчинга снова значим: голова списка нас не волнует (и выполняется второе условие) только в том случае, если первое условие не совпало. Ещё один важный момент - для раскручивания списка в этом случае задаётся новая переменная, и она используется в дальнейшей раскрутке стека, а при возврате её значение увеличивается на единицу и присваивается искомой переменной. Обобщим:
И всё! теперь можно записывать готовое решение:
Тест:
Рекомендую просмотреть действие программы под отладчиком - это гораздо нагляднее. А потом отладить diffLast([1,2,3,1,4,5,1], 4). для постижения дао. Алгоритм программы очень наглядный, но двупроходной - сначала список раскручивается для поиска последнего элемента, а потом, повторно, для поиска не совпадающих с ним элементов. Я набросал однопроходной алгоритм. Вопрос в том, что сам не знаю - эффективнее ли получилось... Просто для справки и сравнения:
однако первый алгоритм гораздо нагляднее, и эффективнее с точки зрения проектирования программ в функциональной парадигме. |
||||||||||||||||||||||||
|
|||||||||||||||||||||||||
![]()
|
| Правила форума "Центр помощи" | |
|
|
ВНИМАНИЕ! Прежде чем создавать темы, или писать сообщения в данный раздел, ознакомьтесь, пожалуйста, с Правилами форума и конкретно этого раздела.
Более подробно с правилами данного раздела Вы можете ознакомится в этой теме. Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Poseidon, Rodman |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Центр помощи | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |