Python

Построение бинарных (двоичных) деревьев худо-бедно разобрал, одно только мало понятно (...)

Цикл..
 for x in v: 
t.append(Node(x))
..добавляет новые узлы дерева. Вот только куда именно он их добавляет? В оперативную память?
Что-либо добавляют обычно в массивы и т. п., а тут просто возращается узел, его родитель и флаг о том добавлять новый узел или нет.
 class Node: 
def __init__(self, data):
self.data = data
self.left = self.right = None
# вершина
# data - поочередно элементы списка [10, 5, 7, 16, 13, 2, 20]


class Tree:
def __init__(self):
self.root = None
# указатель на узел. Изначально пустой

def __find(self, node, parent, value):
# начинаем поиск с корневой вершины
# если значение value (Node(x)) из цикла меньше чем в корневой вершине - идем по левой ветви, иначе по правой
# в новой вершине повторяем это сравнение

if node is None:
return None, parent, False

if value == node.data:
return node, parent, True

if value < node.data:
if node.left:
return self.__find(node.left, node, value)

if value > node.data:
if node.right:
return self.__find(node.right, node, value)

return node, parent, False
# не нашли узел со значение value. К node нужно добавлять новый узел

def append(self, obj):
if self.root is None:
self.root = obj
return obj
# в дереве нет ни одного объекта. Новая вершина добавляется как корневая
# если это условие не сработало, то мы должны найти вершину к которой добавляем новую вершину
# чтобы ее добавить нужно получить ссылку на предыдущую вершину к которой будем цеплять новую вершину
s, p, fl_find = self.__find(self.root, None, obj.data)
# __find ищет родительский узел к которому нужно прицепить новый узел
# он возвращает (НЕ ПРИНИМАЕТ, А ВОЗВРАЩАЕТ) кортеж из трех значений - узел, его родитель, флаг Тру или Фолс
# принимает он следующие параметры
# self.root корень дерева
# None - родительская вершина для корня. У корня нет родителя
# obj.data - данные относительно которых ищем вершину к которой цепляем новую вершину
if not fl_find and s:
if obj.data < s.data:
s.left = obj
else:
s.right = obj
return obj

def show_tree(self, node):
if node is None:
return
self.show_tree(node.left)
print(node.data)
self.show_tree(node.right)


v = [10, 5, 7, 16, 13, 2, 20]
t = Tree()
for x in v:
t.append(Node(x))
t.show_tree(t.root)
Андрей Минаев
Андрей Минаев
5 840
>Вот только куда именно он их добавляет? В оперативную память?
Я так понимаю, что весь курс школьной информатики (принципы Фон-Неймана), основы питона (что такое ссылки и управление питоновой памятью), а также более простые структуры типа списков прошли мимо.

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

>тут просто возращается узел
В поиске __find - "просто" возвращается. Вот здесь:
 if obj.data < s.data:  
s.left = obj // добавляется
else:
s.right = obj // или здесь
Если дерево уже содержит добавляемое значение, то это значение добавляться не будет. Это особенность реализации, а не бинарного дерева как такового.

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

>Что-либо добавляют обычно в массивы
Что-либо добавляют в контейнеры, к которым относятся не только массивы, но списки, деревья и другие структуры

На картинке - односвязный список. Каждый элемент висит в своем каком-то своем блоке (есессно размещённом в оперативке в случайном месте). Если мы создадим новый элемент N, автоматически выделив для него новый блок и затем какую-то ссылку из старых изменим так, чтобы она указывала на него (и естественно ссылку нового элемента сделаем на остаток списка, если вставляем в середину), то при этом говорится, что элемент N был вставлен в список.
Мурат Шахметов
Мурат Шахметов
30 169
Лучший ответ
Данный код отображает создание и работу с бинарным поисковым деревом (binary search tree). Бинарное дерево - это упорядоченная структура данных, состоящая из узлов, в котором каждый узел имеет не более двух потомков: левый и правый. Элементы в левом поддереве меньше родительского узла, а в правом поддереве - больше.

В данном случае у вас есть класс Node, каждый экземпляр которого представляет собой узел вашего дерева. Создание экземпляра Node с определенным значением (Node(x)) инициализирует новый узел с этим значением и задает его левый и правый узлы как None, то есть он еще не имеет потомков.

Класс Tree представляет само дерево. Конструктор создает пустое дерево с корнем None.

Метод append() добавляет новые узлы в дерево по правилам бинарного поискового дерева - значением меньше текущего узла идут влево, больше или равные - вправо.

С помощью этого кода:
 v = [10, 5, 7, 16, 13, 2, 20]  
t = Tree()
for x in v:
t.append(Node(x))
вы создаете новые узлы с данными из списка v и добавляете их к дереву t.

Узлы, или вершины, дерева хранятся в оперативной памяти, причем каждый узел имеет ссылки (указатели) на своих потомков (left, right). Добавление происходит не в массив, а именно в эту структуру данных - дерево, где каждый узел имеет ссылку на своего родителя и на свои дочерние узлы.

Поэтому когда вы говорите, что "цикл добавляет новые узлы", то можно переформулировать это как "цикл создает новые узлы и добавляет их в бинарное дерево". Когда новый узел добавляется в дерево, он занимает свое место в памяти и в структуре дерева, а ссылки на него обновляются у его родительского узла.
Андрей Минаев Еще один бот прилетел. Мне копипаст чатаГПТ не нужен
Андрей Минаев К тому же это дерево никакое не поисковое
Т.е. и красные и чёрные понял?
И графы переходов понял?))
Олег Зябнев
Олег Зябнев
15 040
Андрей Минаев Красно-черные это тоже что-то из бинарных деревьев, слышал про такое, но мне для начала хотя бы это понять до конца
Код реализует построение бинарного (двоичного) дерева поиска. Давайте проанализируем его шаг за шагом.

1. В начале создаются классы `Node` и `Tree`, представляющие узлы дерева и само дерево соответственно.

2. В цикле `for x in v`, создаются узлы дерева и добавляются в дерево `t` с помощью метода `append`.

3. Метод `append` выполняет поиск подходящей позиции для нового узла в дереве. Он использует рекурсивную функцию `__find`, чтобы найти вершину, к которой следует добавить новый узел. Если такая вершина находится, новый узел добавляется в левое или правое поддерево, в зависимости от значения.

4. После добавления всех узлов в дерево, метод `show_tree` используется для вывода значений узлов в отсортированном порядке (возрастающем).

5. В результате, после выполнения кода, выведется содержимое дерева `t` в порядке возрастания: 2, 5, 7, 10, 13, 16, 20.

Чтобы ответить на ваш вопрос, да, новые узлы добавляются в оперативную память. При выполнении метода `append`, создается новый объект типа `Node`, который представляет узел дерева, и он сохраняется в памяти. Когда узел добавляется в дерево, его ссылка (указатель) сохраняется в соответствующем поле `left` или `right` предыдущего узла. Таким образом, дерево строится из отдельных объектов-узлов в памяти.
Никита Муханов Странно, почему автор до сих пор не скрыл этот вырвиглазный текст. Раньше всегда скрывал.