LISP - Дерево
Вы можете строить древовидные структуры данных из cons-ячеек в виде списков списков.
Чтобы реализовать древовидные структуры, вам нужно будет разработать функции, которые будут проходить через cons-ячейки в определенном порядке, например, предварительный порядок, порядок и последующий порядок для двоичных деревьев.
Дерево как список списков
Давайте рассмотрим древовидную структуру, состоящую из cons-ячеек, которые образуют следующий список списков:
((1 2) (3 4) (5 6)).
Схематически это можно было бы выразить как -
Древовидные функции в LISP
Хотя в большинстве случаев вам нужно будет написать свои собственные древовидные функции в соответствии с вашими конкретными потребностями, LISP предоставляет некоторые древовидные функции, которые вы можете использовать.
Помимо всех функций списка, следующие функции работают особенно с древовидными структурами:
Sr. No. | Описание функции |
---|---|
1 | copy-tree x & необязательный vecp Он возвращает копию дерева cons-ячеек x. Он рекурсивно копирует как car, так и cdr направления. Если x не является cons-ячейкой, функция просто возвращает x без изменений. Если необязательный аргумент vecp истинен, эта функция копирует векторы (рекурсивно), а также cons-ячейки. |
2 | tree-equal xy & ключ: тест: тест-не: ключ Он сравнивает два дерева cons-ячеек. Если x и y являются cons-ячейками, их автомобили и cdr сравниваются рекурсивно. Если ни x, ни y не являются cons-ячейкой, они сравниваются с помощью eql или в соответствии с указанным тестом. Функция: key, если она указана, применяется к элементам обоих деревьев. |
3 | subst новое старое дерево и ключ: test: test-not: key Он заменяет вхождения данного старого элемента новым элементом в дереве , которое представляет собой дерево cons-ячеек. |
4 | nsubst новое старое дерево и ключ: test: test-not: key Он работает так же, как subst, но разрушает исходное дерево. |
5 | sublis дерево списка и ключ: test: test-not: key Он работает так же, как и subst, за исключением того, что принимает список ассоциаций, состоящий из старых и новых пар. Каждый элемент дерева (после применения функции: key, если она есть) сравнивается с автомобилями из alist; если он совпадает, он заменяется соответствующим cdr. |
6 | nsublis дерево списка и ключ: test: test-not: key Работает так же, как sublis, но в деструктивной версии. |
Пример 1
Создайте новый файл исходного кода с именем main.lisp и введите в него следующий код.
(setq lst (list '(1 2) '(3 4) '(5 6)))
(setq mylst (copy-list lst))
(setq tr (copy-tree lst))
(write lst)
(terpri)
(write mylst)
(terpri)
(write tr)
Когда вы выполняете код, он возвращает следующий результат -
((1 2) (3 4) (5 6))
((1 2) (3 4) (5 6))
((1 2) (3 4) (5 6))
Пример 2
Создайте новый файл исходного кода с именем main.lisp и введите в него следующий код.
(setq tr '((1 2 (3 4 5) ((7 8) (7 8 9)))))
(write tr)
(setq trs (subst 7 1 tr))
(terpri)
(write trs)
Когда вы выполняете код, он возвращает следующий результат -
((1 2 (3 4 5) ((7 8) (7 8 9))))
((7 2 (3 4 5) ((7 8) (7 8 9))))
Создание собственного дерева
Давайте попробуем построить собственное дерево, используя функции списка, доступные в LISP.
Сначала давайте создадим новый узел, содержащий некоторые данные
(defun make-tree (item)
"it creates a new node with item."
(cons (cons item nil) nil)
)
Затем давайте добавим в дерево дочерний узел - он возьмет два узла дерева и добавит второе дерево как дочернее по отношению к первому.
(defun add-child (tree child)
(setf (car tree) (append (car tree) child))
tree)
Эта функция вернет первого дочернего элемента данного дерева - она возьмет узел дерева и вернет первый дочерний элемент этого узла или ноль, если этот узел не имеет дочернего узла.
(defun first-child (tree)
(if (null tree)
nil
(cdr (car tree))
)
)
Эта функция вернет следующего одноуровневого узла данного узла - она принимает узел дерева в качестве аргумента и возвращает ссылку на следующий одноуровневый узел или ноль, если узел не имеет такового.
(defun next-sibling (tree)
(cdr tree)
)
Наконец, нам нужна функция для возврата информации в узле -
(defun data (tree)
(car (car tree))
)
пример
В этом примере используются вышеуказанные функции -
Создайте новый файл исходного кода с именем main.lisp и введите в него следующий код.
(defun make-tree (item)
"it creates a new node with item."
(cons (cons item nil) nil)
)
(defun first-child (tree)
(if (null tree)
nil
(cdr (car tree))
)
)
(defun next-sibling (tree)
(cdr tree)
)
(defun data (tree)
(car (car tree))
)
(defun add-child (tree child)
(setf (car tree) (append (car tree) child))
tree
)
(setq tr '((1 2 (3 4 5) ((7 8) (7 8 9)))))
(setq mytree (make-tree 10))
(write (data mytree))
(terpri)
(write (first-child tr))
(terpri)
(setq newtree (add-child tr mytree))
(terpri)
(write newtree)
Когда вы выполняете код, он возвращает следующий результат -
10
(2 (3 4 5) ((7 8) (7 8 9)))
((1 2 (3 4 5) ((7 8) (7 8 9)) (10)))