Популярные услуги

Все письменные КМ под ключ за 3 суток! (КМ-6 + КМ-7 + КМ-8 + КМ-9 + КМ-10)
КМ-6. Динамические массивы. Семинар - выполню любой вариант!
Любая задача на C/C++
Одно любое задание в mYsql
Любой тест по базам данных максимально быстро на хорошую оценку - или верну деньги!
Любой реферат по объектно-ориентированному программированию (ООП)
Повышение уникальности твоей работе
КМ-2. Разработка простейших консольных программ с использованием ООП + КМ-4. Более сложные элементы ООП - под ключ!
Оба семинара по программированию под ключ! КМ-2. Разработка циклических алгоритмов + КМ-3. Функции и многофайловые программы в Си
Любой реферат по информатике

Списки

2021-03-09СтудИзба

7. Лекция: Списки

Списки. Рекурсивное определение списка. Операции над списками.

В императивных языках, как правило, основной структурой данных являются массивы. В Прологе так же, как и в Лиспе, основным составным типом данных является список. В этой лекции мы займемся изучением именно списков.

Дадим сначала неформальное определение списка.

Будем называть списком упорядоченную последовательность элементов произвольной длины.

Список задается перечислением элементов списка через запятую в квадратных скобках, так, как показано в приведенных ниже примерах.

Рекомендуемые материалы

[monday, tuesday, wednesday, thursday, friday, saturday, sunday] — список, элементами которого являются английские названия дней недели;

["понедельник", "вторник", "среда", "четверг", "пятница", "суббота", "воскресенье"] — список, элементами которого являются русские названия дней недели;

[1, 2, 3, 4, 5, 6, 7] — список, элементами которого являются номера дней недели;

['п', 'в', 'с', 'ч', 'п', 'с', 'в'] — список, элементами которого являются первые символы русских названий дней недели;

[] — пустой список, т.е. список, не содержащий элементов (в языке функционального программирования Лисп он обозначается nil).

Элементы списка могут быть любыми, в том числе и составными объектами. В частности, элементы списка сами могут быть списками.

В разделе описания доменов списки описываются следующим образом:

DOMAINS

<имя спискового домена>=<имя домена элементов списка>*

Звездочка после имени домена указывает на то, что мы описываем список, состоящий из объектов соответствующего типа.

Например:

listI = integer* /* список, элементы которого —

                    целые числа */

listR = real* /* список, состоящий из вещественных

                 чисел */

listC = char* /* список символов */

lists = string* /* список, состоящий из строк */

listL = listI* /* список, элементами которого являются

                  списки целых чисел */

Последнему примеру будут соответствовать списки вида:

[[1,3,7],[],[5,2,94],[–5,13]]

В классическом Прологе элементы списка могут принадлежать разным доменам, например: [monday, 1, "понедельник"]

В Турбо Прологе, в связи со строгой типизацией, все элементы списка должны принадлежать одному домену. Однако можно разместить в одном списке объекты разной природы, используя домен с соответствующими альтернативами.

Например, следующее описание:

DOMAINS

element = i(integer); c(char); s(string)

listE = element*

позволит иметь дело со списками вида

[i(–15), s("Мама"),c('A'),s("мыла"),c('+'),s("раму"),

i(48),c('!')]

Дадим рекурсивное определение списка.

список — это структура данных, определяемая следующим образом:

  1. пустой список ([ ]) является списком;
  2. структура вида [H|T] является списком, если H — первый элемент списка (или несколько первых элементов списка, перечисленных через запятую), а T — список, состоящий из оставшихся элементов исходного списка.

Принято называть H головой списка, а T — хвостом списка. Заметим, что выбор переменных для обозначения головы и хвоста не случаен. По-английски голова — Head, а хвост — Tail.

Фактически операция "|" позволяет разделить список на хвост и голову (в Лиспе есть подобные операции car и cdr) или, наоборот, приписать объект (объекты) к началу списка (cons в Лиспе).

Данное определение позволяет организовывать рекурсивную обработку списков, разделяя непустой список на голову и хвост. Хвост, в свою очередь, также является списком, содержащим меньшее количество элементов, чем исходный список. Если хвост не пуст, его также можно разбить на голову и хвост. И так до тех пор, пока мы не доберемся до пустого списка, у которого нет головы.

Например, в списке [1, 2, 3] элемент 1 является головой, а список [2, 3] — хвостом, т.е. [1, 2, 3] = [1|[2, 3]].

Заметим, что хвост этого списка [2, 3], в свою очередь, может быть представлен в виде головы 2 и хвоста [3], а список [3] можно рассматривать в виде головы 3 и хвоста []. Пустой список далее не разделяется.

В итоге получаем, что список [1, 2, 3] эквивалентен списку [1|[2, 3]], который, в свою очередь, эквивалентен списку [1|[2|[3]]]. Последний сопоставим со списком [1|[2|[3|[ ]]]].

В этом же списке можно выделить два первых элемента и хвост из третьего элемента [1,2|[3]]. И, наконец, возможен вариант разбиения на голову из трех первых элементов и пустой хвост: [1, 2, 3|[]].

Чтобы организовать обработку списка, в соответствии с приведенным выше рекурсивным определением, нам достаточно задать предложение (правило или факт, определяющее, что нужно делать с пустым списком), которое будет базисом рекурсии, а также рекурсивное правило, устанавливающее порядок перехода от обработки всего непустого списка к обработке его хвоста. Иногда базис рекурсии записывается не для пустого, а для одно- или двухэлементного списка.

В качестве резюме к нашим рассуждениям запишем еще раз определение списка в нотации Бэкуса–Науэра:

Список ::= [ ]|[Элемент <,Элемент>*]|[Голова|Хвост]

Голова ::= Элемент <,Элемент>*

Хвост ::= Список

Словесно это можно записать так: список или пустой, или представим в виде перечисления элементов, записанных через запятую, или состоит из головы и хвоста, который, в свою очередь, также является списком.

Рассмотрим обработку списков.

Пример. Создадим предикат, позволяющий вычислить длину списка, т.е. количество элементов в списке.

Для решения этой задачи воспользуемся очевидным фактом, что в пустом списке элементов нет, а количество элементов непустого списка, представленного в виде объединения первого элемента и хвоста, равно количеству элементов хвоста, увеличенному на единицу. Запишем эту идею:

length([], 0). /* в пустом списке элементов нет */

length([_|T], L) :–

              length(T, L_T), /* L_T — количество

                                 элементов в хвосте */

              L = L_T + 1. /* L — количество элементов

                              исходного списка */

Обратите внимание, что при переходе от всего списка к его хвосту нам неважно, чему равен первый элемент списка, поэтому мы используем анонимную переменную.

Разберем на примере, как это будет работать. Пусть нас интересует количество элементов в списке [1,2,3]. Запишем соответствующий вопрос Пролог-системе:

length([1,2,3],X).

Система попытается вначале сопоставить нашу цель с первым предложением length([], 0), однако ей это не удается сделать, потому что первый аргумент цели является непустым списком. Система переходит ко второму предложению процедуры. Сопоставление с заголовком правила проходит успешно, переменная X связывается с переменной L, список [1,2,3] будет сопоставлен со списком [_|T], переменная T будет конкретизирована значением [2,3]. Теперь система переходит к попытке достижения подцели length(T,L_T). Как и в предыдущем случае, первое предложение с подцелью не сопоставляется, так как список T не пустой. При сопоставлении заголовка правила с подцелью хвост T конкретизируется одноэлементным списком [3]. На следующем шаге рекурсии переменная T означена пустым списком (хвост одноэлементного списка). И, значит, наша подцель выглядит следующим образом: length([], L_T). Эта цель сопоставляется с фактом, переменная L_T становится равной нулю. Раскручивается обратный ход рекурсии: переменная L_T увеличивается на единицу, результат попадает в переменную L. Получаем, что длина списка [3] равна единице. На следующем обратном шаге происходит еще одно добавление единицы, после чего длина списка [2,3] конкретизируется двойкой. И, наконец, на последнем возвратном шаге получаем означивание переменной L числом 3 (количеством элементов в списке [1,2,3]).

Пример. Создадим предикат, позволяющий проверить принадлежность элемента списку. Предикат будет иметь два аргумента: первый — искомое значение, второй — список, в котором производится поиск.

Построим данный предикат, опираясь на тот факт, что объект принадлежит списку, если он либо является первым элементом списка, либо элементом хвоста. Это может быть записано в виде двух предложений:

member(X,[X|_]). /* X — первый элемент списка */

member(X,[_|T]) :–

                member(X,T). /* X принадлежит хвосту T*/

Заметим, что в первом случае (когда первый элемент списка совпадает с исходным элементом), нам неважно, какой у списка хвост, и можно в качестве хвоста указать анонимную переменную. Аналогично, во втором случае, если X принадлежит хвосту, нам не важно, какой элемент первый.

Отметим, что описанный предикат можно использовать двояко: во-первых, конечно, для того, для чего мы его и создавали, т.е. для проверки, имеется ли в списке конкретное значение. Мы можем, например, поинтересоваться, принадлежит ли двойка списку [1, 2, 3]:

member(2, [1, 2, 3]).

Получим, естественно, ответ: "Yes".

Подобным образом можно спросить, является ли число 4 элементом списка [1, 2, 3]:

member(4, [1, 2, 3]).

Ответом, конечно, будет "No".

Второй способ использования данного предиката — это получение по списку его элементов. Для этого нужно в качестве первого аргумента предиката указать свободную переменную. Например:

member(X, [1, 2, 3]).

В качестве результата получим список всех элементов списка:

X=1

X=2

X=3

Третий способ позволит получить по элементу варианты списков, которые могут его содержать. Теперь свободную переменную запишем вторым аргументом предиката, а первым — конкретное значение. Например,

member(1, X).

Вначале Пролог-система выдаст предупреждение о том, что переменная X не связана в первом предложении ("708 WARNING: The variable is not bound in this clause. (F10=ok, Esc=abort)").

У нас есть два способа отреагировать на это предупреждение: нажать кнопку Esc, чтобы отказаться от генерации списков, содержащих единицу в качестве элемента; нажать F10 для того, чтобы продолжить выполнение цели. Во втором случае Пролог-система начнет выдавать варианты списков, содержащих единицу:

X=[1|_] /* единица — первый элемент списка */

X=[_,1|_] /* единица — второй элемент списка */

X=[_,_,1|_] /* единица — третий элемент списка */

и т.д.

Этот процесс будет продолжаться до тех пор, пока не будет нажата комбинация клавиш Ctrl+Break.

Если данный предикат планируется использовать только первым способом, то можно ускорить его работу, устранив поиск элемента в хвосте списка, если он уже найден в качестве первого элемента списка. Это можно сделать двумя способами.

Первый способ. Добавим в правило проверку на несовпадение первого элемента списка с искомым элементом, чтобы поиск элемента в хвосте списка производился только тогда, когда первый элемент списка не является искомым. Модифицированный предикат будет выглядеть следующим образом:

member2(X,[X|_]).

member2(X,[Y|T]):–

                  X<>Y, member2(X,T).

Заметим, что эту модификацию предиката member нельзя использовать для получения всех элементов списка. Если подставить в качестве первого аргумента несвязанную переменную, то при попытке согласования подцели правила неозначенная переменная X будет сравниваться с неозначенной переменной Y. Получим сообщение об ошибке "Free variable in expression".

Второй способ. Добавим в факт отсечение, чтобы в ситуации, когда искомый элемент оказался первым элементом списка, не производился лишний поиск в хвосте исходного списка. Получим:

member3(X,[X|_]):–!.

member3(X,[_|T]):–

                  member3(X,T).

Заметим, что хотя эта модификация предиката member более эффективна, чем исходная, за счет того, что она не выполняет поиск в хвосте после того, как искомый элемент найден, ее можно использовать только для того, чтобы проверить, имеется ли в списке конкретное значение. Если мы попытаемся применить ее для получения всех элементов списка, подставив в качестве первого аргумента несвязанную переменную, то результатом будет только первый элемент списка. Отсечение не позволит нам получить оставшиеся элементы.

Пример. Создадим предикат, позволяющий соединить два списка в один. Первые два аргумента предиката будут представлять соединяемые списки, а третий — результат соединения.

В качестве основы для решения этой задачи возьмем рекурсию по первому списку. Базисом рекурсии будет факт, устанавливающий, что если присоединить к списку пустой список, в результате получим исходный список. Шаг рекурсии позволит создать правило, определяющее, что для того, чтобы приписать элементы списка, состоящего из головы и хвоста, ко второму списку, нужно соединить хвост и второй список, а затем к результату приписать спереди первый элемент первого списка. Запишем решение:

conc([ ], L, L). /* при присоединении пустого списка

                    к списку L получим список L */

conc([H|T], L, [H|T1]) :–

conc(T,L,T1). /* соединяем хвост и список L, получаем

                 хвост результата */

Заметим, что этот предикат также можно применять для решения нескольких задач.

Во-первых, для соединения списков. Например, если задать вопрос

conc([1, 2, 3], [4, 5], X)

то получим в результате

X= [1, 2, 3, 4, 5]

Во-вторых, для того, чтобы проверить, получится ли при объединении двух списков третий. Например, на вопрос:

conc([1, 2, 3], [4, 5], [1, 2, 5]).

ответом будет, конечно, No.

В-третьих, можно использовать этот предикат для разбиения списка на подсписки. Например, если задать следующий вопрос:

conc([1, 2], Y, [1, 2, 3]).

то ответом будет Y=[3].

Аналогично, на вопрос

conc(X, [3], [1, 2, 3]).

получим ответ X=[1, 2].

И, наконец, можно спросить

conc(X, Y, [1, 2, 3]).

Получим четыре решения:

X=[], Y=[1, 2, 3]

X=[1], Y=[2, 3]

X=[1, 2], Y=[3]

X=[1, 2, 3], Y=[]

В-четвертых, можно использовать этот предикат для поиска элементов, находящихся левее и правее заданного элемента. Например, если нас интересует, какие элементы находятся левее и, соответственно, правее числа 2, можно задать следующий вопрос:

conc(L, [2|R], [1, 2, 3, 2, 4]).

Получим два решения:

L=[1], R=[3, 2, 4].

L=[1, 2, 3], R=[4]

В-пятых, на основе нашего предиката conc можно создать предикат, находящий последний элемент списка:

last(L,X):–

          conc(_,[X],L).

Справедливости ради стоит заметить, что этот предикат можно реализовать и "напрямую", без использования предиката conc:

last2([X],X). /* последний элемент одноэлементного

                 списка — этот элемент */

last2([_|L],X):–

        last2(L,X). /* последний элемент списка совпадает

                       с последним элементом хвоста */

В-шестых, можно определить, используя conc, предикат, позволяющий проверить принадлежность элемента списку. При этом воспользуемся тем, что если элемент принадлежит списку, то список может быть разбит на два подсписка так, что искомый элемент является головой второго подсписка:

member4(X,L):–

             conc(_,[X|_],L).

В-седьмых, используя предикат, позволяющий объединить списки, можно создать предикат, проверяющий по двум значениям и списку, являются ли эти значения соседними элементами списка. Предикат будет иметь три параметра: первые два — значения, третий — список.

Идея решения заключается в следующем. Если два элемента оказались соседними в списке, значит, этот список можно разложить на два подсписка, причем голова второго подсписка содержит два наших элемента в нужном порядке. Выглядеть это будет следующим образом:

neighbors(X,Y,L):–

     conc(_,[X,Y|_],L). /* список L получается путем

                           объединения некоторого списка

                           со списком, голову которого

                           составляют элементы X и Y */

Обратите внимание, что этот предикат проверяет только наличие нужных значений в указанном порядке. Если нам неважен порядок, в котором два данных значения встречаются в некотором списке, то следует записать модификацию описанного выше предиката, которая будет проверять оба варианта размещения искомых элементов. Для этого достаточно, чтобы список раскладывался на два подсписка, причем голова второго подсписка содержала два наших элемента либо в прямом, либо в обратном порядке. Соответствующий программный код будет следующим:

neighbors2(X,Y,L):–

          conc(_,[X,Y|_],L);

          conc(_,[Y,X|_],L). /* список L получается

                       путем объединения некоторого

                       списка со списком, голову

                       которого составляют элементы X

                       и Y или элементы Y и X */

Есть подозрение, что многообразие использований предиката conc приведенными выше примерами не исчерпывается.

Пример. Разработаем предикат, позволяющий "обратить" список (записать его элементы в обратном порядке). Предикат будет иметь два аргумента: первый — исходный список, второй — список, получающийся в результате записи элементов первого аргумента в обратном порядке.

Для решения этой задачи воспользуемся рекурсией. Базис: если записать элементы пустого списка (которых нет) в обратном порядке — опять получим пустой список. Шаг рекурсии: для того чтобы получить "перевернутый" список, можно "перевернуть" его хвост и "приклеить" к нему первый элемент исходного списка. Запишем эти размышления.

reverse([ ],[ ]). /* обращение пустого списка дает пустой

                     список*/

reverse([X|T],Z):–

             reverse(T,S), conc(S,[X],Z).

                  /* обращаем хвост и приписываем к нему

                     справа первый элемент исходного

                     списка*/

Обратите внимание, что вторым аргументом в предикате conc должен стоять именно одноэлементный список [X], а не элемент X. Это связано с тем, что аргументами предиката conc должны быть списки.

Можно написать данный предикат без использования предиката conc. Правда, тогда нам придется добавить дополнительный аргумент, в котором мы будем "накапливать" результат. Мы будем "отщипывать" от исходного списка по элементу и дописывать его к вспомогательному списку. Когда исходный список будет исчерпан, мы передадим "накопленный" список в третий аргумент в качестве ответа. До этого момента третий аргумент передается от шага к шагу неконкретизированным. Реализация будет выглядеть следующим образом:

rev([H|T],L1,L2):–

             rev(T,[H|L1],L2). /* голову первого

                                  аргумента дописываем ко

                                  второму аргументу*/

rev([ ],L,L). /* если исходный список закончился,

                 то второй аргумент — передаем в третий

                 аргумент в качестве результата*/

Для того чтобы использовать этот предикат обычным "двухаргументным" образом, добавим еще один предикат, который будет запускать наш "основной" предикат rev, имеющий "лишний" аргумент, используемый для накопления элементов обращенного списка. В начале работы второй аргумент должен быть пустым списком.

reverse2(L1,L2):–

             rev (L1,[ ],L2).

Пример. Создадим предикат, который позволит проверить, является ли список палиндромом. Палиндромом называется список, который совпадает со своим обращением. Соответственно, у данного предиката будет всего один аргумент (список, который проверяем на "палиндромность").

Первое, что приходит в голову: воспользоваться только что написанным предикатом reverse (или reverse2). Перевернуть список и проверить, совпадает ли результат с исходным списком. Выглядеть этот предикат будет следующим образом:

palindrom(L):–

             reverse (L,L).

Можно решить эту задачу "напрямую", без использования предиката reverse.

Пример. Напишем предикат, позволяющий получать элемент списка по его номеру так же, как по номеру можно получать элемент массива в императивных языках программирования. Предикат будет трехаргументный: первый аргумент — исходный список, второй аргумент — номер элемента и третий — элемент списка, указанного в качестве первого аргумента предиката, имеющий номер, указанный в качестве второго аргумента.

Решение проведем рекурсией по номеру элемента. В качестве базиса возьмем очевидный факт, что первым элементом списка является его голова. Шаг рекурсии позволит нам сделать предположение, что N-й элементом списка является (N–1)-м элементом хвоста. Данному определению будет соответствовать следующее предложение:

n_element([X|_],1,X).

n_element([_|L],N,Y):–

                N1=N–1,

                n_element(L,N1,Y).

Пример. В большинстве практических задач не обойтись без предиката, удаляющего все вхождения заданного значения из списка. Предикат будет зависеть от трех параметров. Первый параметр будет соответствовать удаляемому списку, второй — исходному значению, а третий — результату удаления из первого параметра всех вхождений второго параметра. Создадим его.

Без рекурсии не обойдется и на этот раз. Если первый элемент окажется удаляемым, то нужно перейти к удалению заданного значения из хвоста списка. Результатом в данном случае должен стать список, полученный путем удаления всех вхождений искомого значения из хвоста первоначального списка. Это даст нам базис рекурсии. Шаг рекурсии будет основан на том, что если первый элемент списка не совпадает с тем, который нужно удалять, то он должен остаться первым элементом результата, и нужно переходить к удалению заданного значения из хвоста исходного списка. Полученный в результате этих удалений список должен войти в ответ в качестве хвоста.

delete_all(_,[],[]).

delete_all(X,[X|L],L1):–

                  delete_all (X,L,L1).

delete_all (X,[Y|L],[Y|L1]):–

                  X<>Y,

                  delete_all (X,L,L1).

Если нам нужно удалить не все вхождения определенного значения в список, а только первое, то следует немного изменить вышеописанную процедуру. Это можно сделать несколькими способами. Рассмотрим один из них.

Заменим в первом правиле рекурсивный вызов предиката отсечением. В этом случае, пока первый элемент списка не окажется удаляемым, мы будем переходить к рассмотрению хвоста.

delete_one(_,[],[]).

delete_one(X,[X|L],L):–!.

delete_one(X,[Y|L],[Y|L1]):–

                  delete_one(X,L,L1).

В заключение лекции рассмотрим предикат findall, предназначенный для нахождения всех решений некоторой цели. У него три параметра: имя переменной, предикат и список, в который будут помещены найденные решения.

Аппараты с горючими пылями - лекция, которая пользуется популярностью у тех, кто читал эту лекцию.

Пример. Посмотрим, как с помощью предиката findall можно решать задачи, подобные тем, которые мы решали в предыдущей лекции.

Найдем имена всех дочек: findall(N,mother(_,N),L). В список L попадут имена всех дочек.

Найдем имена всех дочек Даши: findall(N,mother("Даша",N),L). В список L попадут имена всех дочек Даши.

Самостоятельные задания

  1. Создайте предикат, заменяющий в исходном списке первое вхождение заданного значения другим.
  2. Создайте предикат, заменяющий в исходном списке все вхождения заданного значения другим.
  3. Создайте предикат, порождающий по заданному натуральному числу N список, состоящий из натуральных чисел от 1 до N (по возрастанию).
  4. Создайте предикат, порождающий по заданному натуральному числу N список, состоящий из натуральных чисел от N до 1 (по убыванию).
  5. Создайте предикат, порождающий по заданному натуральному числу N список, состоящий из N случайных натуральных чисел из промежутка от 1 до 100.
  6. Создайте предикат, порождающий по заданным числам N, M, K список, состоящий из N случайных натуральных чисел из промежутка от M до K.
  7. Создайте предикат, порождающий по заданным числам M, K список, состоящий из случайного количества случайных чисел из промежутка от M до K.
  8. Создайте предикат, порождающий список, состоящий из случайного количества случайных чисел.
  9. Создайте предикат, который увеличивает элементы исходного списка на единицу.
  10. Создайте предикат, переводящий список цифр от 0 до 9 в список соответствующих им названий (строк).
  11. Создайте предикат, переводящий список чисел в список соответствующих им названий.
  12. Создайте предикат, переводящий список цифр от 0 до 9 в список соответствующих им римских чисел.
  13. Создайте предикат, переводящий список арабских чисел в список соответствующих им римских чисел.
  14. Создайте предикат, переводящий список римских чисел в список соответствующих им арабских чисел.
  15. Создайте предикат, удваивающий значения элементов списка.
  16. Создайте предикат, преобразующий список, элементами которого являются числа, в список, элементы которого неотрицательны.
  17. Создайте предикат, преобразующий исходный список в список позиций отрицательных элементов.
  18. Создайте предикат, удаляющий из исходного списка элементы с четными номерами.
  19. Создайте предикат, который разделит исходный список из целых чисел на два списка: список положительных чисел и список отрицательных чисел.
  20. Создайте предикат, разделяющий исходный список на два подсписка. В первый из них должны попасть элементы с нечетными номерами, во второй - элементы с четными номерами.
  21. Создайте предикат, вычисляющий по списку и числу, подсписок исходного списка, начинающийся с элемента с указанным номером.
  22. Создайте предикат, осуществляющий удаление указанного количества последних элементов исходного списка.
  23. Создайте предикат, осуществляющий разделение исходного списка на два подсписка. В первый из них должно попасть указанное количество элементов из начала списка, во второй - оставшиеся элементы.
  24. Создайте предикат, осуществляющий разделение исходного списка на два подсписка. В первый из них должно попасть указанное количество элементов с конца списка, во второй - оставшиеся элементы.
  25. Создайте предикат, находящий предпоследний элемент списка.
  26. Создайте предикат, удаляющий предпоследний элемент списка.
  27. Создайте предикат, заменяющий в исходном списке два подряд идущих одинаковых элемента одним.
  28. Создайте предикат, удаляющий в исходном списке все повторные вхождения элементов.
  29. Создайте предикат, осуществляющий перестановку двух элементов списка с заданными номерами.
  30. Создайте предикат, генерирующий все перестановки элементов списка, указанного в качестве первого аргумента предиката.
  31. Создайте предикат, осуществляющий циклический сдвиг элементов списка на один влево (вправо).
  32. Создайте предикат, осуществляющий циклический сдвиг элементов списка на заданное количество шагов влево (вправо).
  33. Создайте предикат, осуществляющий поэлементное перемножение соответствующих элементов двух исходных списков.
  34. Создайте предикат, вычисляющий скалярное произведение векторов, заданных списками целых чисел.
  35. Создайте предикат, осуществляющий подсчет числа вхождений каждого элемента исходного списка. Ответом должен быть список пар, в которых первая компонента - элемент исходного списка, вторая - число его вхождений в первоначальный список.
  36. Создайте предикат, определяющий первую позицию подсписка в списке.
  37. Создайте предикат, добавляющий элементы одного списка во второй список, начиная с заданной позиции.
  38. Создайте предикат, возвращающий по списку и двум числам M и N подсписок исходного списка, состоящий из элементов с номерами от M до N.
  39. Создайте предикат, формирующий список простых чисел, не превосходящих данного числа.
  40. Создайте предикат, транспонирующий матрицу, заданную списком списков.
Свежие статьи
Популярно сейчас
А знаете ли Вы, что из года в год задания практически не меняются? Математика, преподаваемая в учебных заведениях, никак не менялась минимум 30 лет. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
5160
Авторов
на СтудИзбе
439
Средний доход
с одного платного файла
Обучение Подробнее