Эта заметка является логическим продолжением статьи: Cвойство замыкания, на примере list. Представление последовательностей в виде списков естественно распространить на последовательности, элементы которых сами могут быть последовательностями. Например, мы можем рассматривать объект ((1,2) 3, 4), получаемый с помощью ((1,2),(3, 4)). Как список с тремя членами, первый из которых сам является списком. В сущности, это подсказывается формой, в которой результат печатается интерпретатором. Еще один способ думать о последовательностях последовательностей — деревья (trees). Элементы последовательности являются ветвями дерева, а элементы, которые сами по себе последовательности — поддеревьями. Рисунок снизу показывает структуру в виде дерева.
*-Нравится статья? Кликни по рекламе! :)
Естественным инструментом для работы с деревьями является рекурсия, поскольку часто можно свести операции над деревьями к операциям над их ветвями, которые сами сводятся к операциям над ветвями ветвей, и так далее, пока мы не достигнем листьев дерева. Например, сравним процедуру length из предыдущей статьи с процедурой countLeaves, которая подсчитывает число листьев дерева. Чтобы реализовать countLeaves, вспомним рекурсивную схему вычисления length:
Подобно тому, как map может служить мощной абстракцией для работы с последовательностями, map, совмещенная с рекурсией, служит мощной абстракцией для работы с деревьями. Процедура scaleTree принимает в качестве аргумента числовой множитель и дерево, листьями которого являются числа. Она возвращает дерево той же формы, где каждое число умножено на множитель. Рекурсивная схема scaleTree похожа на схему countLeaves:
Получаем:
Используемая литература:
*-Нравится статья? Кликни по рекламе! :)
- Длина списка x есть 1 плюс длина cdr от x.
- Длина пустого списка есть 0.
- countLeaves от пустого списка равна 0.
- countLeaves от дерева x есть countLeaves от (car x) плюс countLeaves от (cdr x).
- Count-leaves от листа равна 1.
def countLeaves(l): if l is None: return 0 elif not isinstance(l, tuple): return 1 return countLeaves(car(l))+countLeaves(cdr(l))
Порядок первых двух ветвей существен, поскольку пустой список удовлетворяет предикату is None и при этом не является парой.Отображение деревьев
Подобно тому, как map может служить мощной абстракцией для работы с последовательностями, map, совмещенная с рекурсией, служит мощной абстракцией для работы с деревьями. Процедура scaleTree принимает в качестве аргумента числовой множитель и дерево, листьями которого являются числа. Она возвращает дерево той же формы, где каждое число умножено на множитель. Рекурсивная схема scaleTree похожа на схему countLeaves:
def scaleTree(tree, factor): if tree is None: return None elif not isinstance(tree, tuple): return tree*factor else: return (scaleTree(car(tree), factor), scaleTree(cdr(tree), factor))Другой способ реализации scaleTree состоит в том, чтобы рассматривать дерево как последовательность поддеревьев и использовать map. Мы отображаем последовательность, масштабируя по очереди каждое поддерево, и возвращаем список результатов. В базовом случае, когда дерево является листом, мы просто умножаем. Нужно только быть аккуратнее, мы не можем использовать map в чистом виде, который мы описали с вами в прошлой статье. Её нужно немного модифицировать с учетом, что элементы сами являются последовательностями.
Получаем:
def map(proc, l): if l is None: return None elif not isinstance(l, tuple): return proc(l) return (proc(car(l)), map(proc,cdr(l)))
def scaleTree(tree, factor): f=lambda subTree:mapScaleTree(subTree, factor) if isinstance(subTree, tuple) else subTree*factor return map(f, tree)Многие операции над деревьями могут быть реализованы с помощью такого сочетания операций над последовательностями и рекурсии.
Используемая литература:
Комментариев нет:
Отправить комментарий