Структуры данных и алгоритмы
Значение переменной u вычисляется и присваивается ей сразу, после этого оно не изменяется. Значение переменной v вычисляется в момент вызова.
Для определения функций применяются оба вида присваиваний. Почти всюду далее будет использоваться отсроченное присваивание. Например, функцию можно определить следующим образом:
In[10]:= f[x_] := x\^2 + 1 f[3] Out[12]= 10
Конструкции вида f[x_, y_, ...] := g[x, y, ...] называют правилами преобразования выражений. Знак подчеркивания (_) обозначает шаблонное выражение, которое может быть заменено произвольным значением. Выражение x_ обозначает шаблон с присвоенным ему именем x. Оно применяется для передачи объекта внутри функциональных конструкций. В правой части переменные используются без знака подчеркивания. Когда в коде встретится выражение, которое сопоставляется с левой частью, оно будет заменено только что вычисленным значением правой части.
Если для определения функции f используется несколько правил, то для вычисления значения выражения f[expr] применяется последнее из правил с одинаковой левой частью:
In[13]:= f[0] := 0 f[x_] := x + 1 f[x_] := x - 1 f[0] := 5 {f[2], f[1], f[0], f[-1], f[a]} Out[17]= {1, 0, 5, - 2, - 1 + a}
Более частное определение правила предшествует более общему. Например, ниже для вычисления g[0] используется первое правило, а не второе; если правила поменять местами, то результат не изменится:
In[18]:= g[0] := 0 g[x_] := 1/x {g[2], g[1], g[0], g[-1]} Out[20]= {1/2, 1, 0, -1}
Для условного задания функций используются встроенные функции If и Which. Например, рассмотрим функции
Функция If соответствует конструкции "если …, то …, иначе …". С ее помощью функцию h можно определить следующим образом:
In[21]:= h[x_] := If[x > 0, Log[2, x], 0] {h[8], h[4], h[2], h[0], h[-2]} Out[22]= {3, 2, 1, 0, 0}
Функция Which является обобщением функции If. Она может содержать произвольное число условных выражений. Используем ее для определения функции sgn:
In[23]:= sgn[x_] = Which[x>0, 1, x==0, 0, x<0, -1]; {sgn[-3], sgn[0], sgn[3]} Out[24]= {-1, 0, 1}
Отменить определение функций и очистить переменные можно с помощью функции Clear:
In[25]:=Clear[f, g]; {f[1], g[1]} Out[26]= {f[1], g[1]}
Рассмотрим функцию вычисления k-го члена последовательности Фибоначчи 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, … Вместе с шаблоном укажем тип переменной: значение функции будет вычисляться только для целых положительных значений аргумента. Сначала определим функцию следующим образом:
In[27]:= f[1] = f[2] = 1; f[k_Integer?Positive] := f[k - 1] + f[k - 2] {f[2], f[3], f[8], f[9], f[10]} f[0] Out[29]= {1, 2, 21, 34, 55} Out[30]= f[0]
В этом случае для некоторых запросов, например f[50], система может прерывать вычисления из-за превышения временных ограничений.
Определение функции Fibonacci, которое указано ниже, приводит к существенному сокращению рекурсивных вызовов. В этом определении используется вспомогательная функция g, два последних аргумента которой хранят два соседних члена последовательности:
In[31]:= fibonacci[k_Integer?Positive] := g[k, 0, 1] g[0, m_, _] := m g[k_, m_, n_] := g[k - 1, n, m + n] {fibonacci[8], fibonacci[9], fibonacci[10]} fibonacci[144] Out[34]= {21, 34, 55} Out[35]= 555 565 404 224 292 694 404 015 791 808
Более быстрое вычисление значений функции Фибоначчи можно получить, если использовать ее первое определение, но при этом запоминать каждое вычисленное значение:
In[36]:= fib[1] = fib[2] = 1; fib[n_Integer?Positive]:=fib[n]=fib[n-1]+fib[n-2] fib[200] Out[38]=280 571 172 992 510 140 037 611 932 413 038 677 189 525
Более подробное введение в определение и использование функций в языке Wolfram содержится в [3, 12].
Результаты вычислений сохраняются во время работы с программой - вычислительной сессии. По умолчанию сессия начинается при открытии программы и заканчивается при ее закрытии. Можно прекратить сессию и начать другую с помощью команды меню Evaluation -> Restart Session. В этом случае все вычисления можно будет произвести заново.
Линейные структуры данных. Список
Рассмотрим модели типов данных список, стек, очередь и дек, которые представляют линейные, или одномерные структуры данных.
Для представления линейной структуры данных в виде терма будет использоваться два функциональных символа - 0-арный символ nil для обозначения пустой структуры и бинарный символ cons для обозначения непустой. Например, список [1, 2, 3] представляется в виде cons(1, cons(2, cons(3, nil))).
Откроем в облаке Wolfram новый файл и введем код:
In[1]:= x = cons[1, cons[2, cons[3, nil]]]; TreeForm[x] ( Shift+Enter )
Представление данного терма в виде дерева показано на рис. 6.2.
Список - это конечная последовательность элементов, которая записывается в виде [1, 2, 3] для непустого списка или [] для пустого (в языке Wolfram для списков используются фигурные скобки).
Элементы списка нумеруются с нуля, слева направо. Например, если список имеет вид ["Иванов", "Петров", "Сидоров"], то его элементом с индексом 2 является "Сидоров". Первый элемент списка называется его головой, а список последующих элементов - его хвостом. Для приведенного выше списка головой является "Иванов", а хвостом - список ["Петров", "Сидоров"].