представление дерева в виде списка в python

66
9

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

Есть ли что-то неправильное в хранении узлов дерева в виде списка в python? что-то вроде:

[0,1,2,3,4,5,6,7,8]

где 0-я позиция по умолчанию равна 0, 1 - корень, а для каждой позиции (i) 2i и 2i + 1 позиции являются дочерними. Когда ни один ребенок не присутствует, у нас просто есть "Нет" в этой позиции.

Я прочитал пару книг/заметок, где они представляют дерево, используя список списков, или что-то более сложное, чем просто простой список, подобный этому, и мне было интересно, есть ли что-то по своей сути неправильно в том, как я смотрю на него?

спросил(а) 2021-01-27T19:13:17+03:00 8 месяцев, 3 недели назад
1
Решение
102

Вы, конечно, МОЖЕТЕ это сделать. Я бы определил его как класс, полученный из списка с помощью метода get_children. Однако это довольно уродливо, так как либо A) вам нужно предварительно обработать весь список в O (n) раз, чтобы соединить индексы со значениями или B) вам нужно будет вызвать list.index в O (n log n) времени чтобы пересечь дерево.

class WeirdBinaryTreeA(list):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def get_children(value):
"""Calls list.index on value to derive the children"""
idx = self.index(value) # O(n) once, O(n log n) to traverse
return self[idx * 2], self[idx * 2 + 1]

class WeirdBinaryTreeB(list):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__mapping = self.processtree()

def processtree(self):
for idx, val in enumerate(self):
self.__mapping[val] = idx

def get_children(value):
"""Queries the mapping on value to derive the children"""
idx = self.__mapping[value] # O(1) once, O(n) to traverse
return self[idx * 2], self[idx * 2 + 1]

Однако главный вопрос: зачем вы это делаете? Что делает его лучше, чем список списков или диктофон? Что происходит, когда у вас есть:

    A
/ \
B
/ \
C
/ \
D
/ \
E
/ \
F

И ваш список выглядит так:

[0, 'A', None, 'B', None, None, None, 'C', None, None, None, None, None, None, None, 'D', ...]

Вместо:

{"A": {"B": {"C": {"D": {"E": {"F": None}}}}}}

ответил(а) 2021-01-27T19:13:17+03:00 8 месяцев, 3 недели назад
46

Я видел такие представления, как этот (ваш плоский список/массив), используемый в коде C, и подобные представления могут быть приемлемыми и в Python, но это зависит от характера обрабатываемых вами данных. В коде C сбалансированное дерево в этом представлении списка может быть очень быстрым для доступа (гораздо быстрее, чем перемещение ряда указателей), хотя преимущество производительности на Python может быть менее заметным из-за всех других накладных расходов.

Для разумно сбалансированных плотных деревьев этот подход с плоским списком является разумным. Однако, как прокомментировал Адам Смит, этот тип дерева с плоскими списками станет чрезвычайно расточительным для несбалансированных редких деревьев. Предположим, у вас есть одна ветка с одинокими детьми, спускающимися со сто уровней, а остальная часть дерева ничего не имела. Вам понадобится 2 ^ 100 + 2 ^ 99 + 2 ^ 98 +... + 2 ^ 1 + 1 пятна в дереве плоских списков. В таком случае вы должны использовать огромное количество памяти для чего-то, что может быть представлено гораздо эффективнее с помощью вложенных списков.


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

ответил(а) 2021-01-27T19:13:17+03:00 8 месяцев, 3 недели назад
46

Нет ничего плохого в том, чтобы хранить двоичное дерево в виде списка так, как вы это делаете, - это та же идея, что хранить его как плоский массив на языке C или Java. Доступ к родительскому элементу данного узла происходит очень быстро, а поиск детей также довольно эффективен.

Я полагаю, что множество примеров и руководств предпочтут использовать представление, которое "действительно имеет форму дерева" (список списков или объектов) - это может быть несколько более интуитивно понятным для объяснения.

ответил(а) 2021-01-27T19:13:17+03:00 8 месяцев, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема