Это довольно обычное двоичное дерево, за исключением того факта, что один из узлов может быть пустым.
Я хотел бы найти способ вывести его горизонтально (то есть кореньузел находится слева и расширяется вправо).
У меня был некоторый опыт расширения деревьев по вертикали (корневой узел вверху, расширение вниз), но я не уверен, с чего начать, в этомcase.
Предпочтительно, он будет следовать следующим правилам:
- Если у узла есть только один дочерний элемент, он может быть пропущен как избыточный («конечный узел», безchildren, всегда отображается)
- Все узлы одинаковой глубины должны быть выровнены по вертикали;все узлы должны находиться справа от всех менее глубоких узлов и слева от всех более глубоких узлов.
- Узлы имеют строковое представление, которое включает их глубину.
- Каждый «конечный узел» имеетсобственная уникальная линия;то есть количество строк - это число конечных узлов в дереве, и когда конечный узел находится в строке, после этой конечного узла в этой строке может не быть ничего другого.
- Как следствиепоследнее правило, корневой узел может быть лучше в верхнем левом или нижнем левом углу;предпочтительным является верхний левый.
Например, это допустимое дерево с шестью конечными узлами (узел представлен именем и его глубиной): РЕДАКТИРОВАТЬ: см. нижнюю часть вопросадля более простого рендеринга
[a0]-----------[b3]------[c5]------[d8]
\ \ \----------[e9]
\ \----[f5]
\-[g1]--------[h4]------[i6]
\ \--------------------[j10]
\-[k3]
, который представляет вертикальное явное двоичное дерево:
0 a
/ \
1 g *
/ \ \
2 * * *
/ \ \
3 k * b
/ / \
4 h * *
/ \ \ \
5 * * f c
/ \ / \
6 * i * *
/ / \
7 * * *
/ / \
8 * * d
/ /
9 * e
/
10 j
(ветви сложены для компактности; *
представляет избыточный, одно-дочерние узлы; обратите внимание, что *
являются фактическими узлами, каждый из которых содержит по одному дочернему узлу, только с именами, опущенными здесь для удобства представления)
(также, чтобы уточнить, я хотелдля генерации первого, горизонтального дерева, а не этого вертикального дерева)
Я говорю не зависимо от языка, потому что я просто ищу алгоритм;Я говорю ruby, потому что в конечном итоге мне все равно придется реализовать его в ruby.
Предположим, что каждая Node
структура данных хранит только свой идентификатор, левый узел и правый узел.
Мастер Tree
класс отслеживает все узлы и имеет адекватные алгоритмы для поиска:
- n-й предок узла
- n-ный потомок узла
- Всепотомки конечного узла узла и их количество
- Генерация узла
- Самый низкий общий предок двух заданных узлов
I ужезнать :
- Количество конечных узлов
У кого-нибудь есть идеи, с чего можно начать?Должен ли я пойти на рекурсивный подход?Повторяющийся?Какой-то Psuedo-код тоже был бы довольно крутым, и его очень ценят =)
progress
По предложению walkytalky, я решил посмотреть, как он будет выглядетьнравится отображать каждый «релевантный» или значимый узел в сетку, где столбцы являются глубиной, а строки - идентифицируемыми по их конечным узлам.Вот что происходит (пропуская столбец 7, потому что в глубине 7 нет значимых узлов):
depth: 0 1 2 3 4 5 6 8 9 10
a b c d
e
f
g h i
j
k
Должно быть достаточно просто сгенерировать эту сетку с помощью поиска в ширину или в глубину.Возможно, наиболее тривиально, просто сохраняя двумерный массив и помещая в него все значимые узлы, вставляя строку для каждого «второго потомка».
Теперь, зная эти факты:
- последний узел в строке должен быть конечным узлом
- Дочерние элементы всегда находятся справа и в той же строке или ниже своего родительского узла.
- Все не конечные узлы должны иметь точно two children
- Следовательно, все неконечные узлы имеют дочерние элементы, которые являются первыми справа от их столбца , первый дочерний элемент находится в той же строке,вторым потомком является n строк под ними, где n - количество узлов в правой части от него.
Мы можем видеть, что для любой действительной сетки существует один однозначный способ , так сказать, «соединить точки»;здесь представлено одно недвусмысленное дерево.
Теперь «соединение точек» больше не является вопросом бинарной древовидной структуры ... это просто вопрос декорирования.Нам просто нужно построить алгоритм для правильного размещения правильных -
и \
, куда они могут пойти, возможно, следуя только простым сеткам / лексикографическим правилам вместо двоичной древовидной структурыправила.
По сути, это означает, что проблема рендеринга дерева теперь намного проще, чем рендеринг сетки с причудливыми декорациями.
Может кто-нибудь предложитьспособ формулирования этих правил?Или, может быть, совершенно другой метод?
edit
Я задумал намного, гораздо более простой финальный рендеринг:
--d0----d1----d3----d4----d5----d6----d8----d9----d10-- => guide line (not rendered)
[a0 ]-------[b3 ]-------[c5 ]-------[d8 ]
| | \---------------[e9 ]
| \---------[f5 ]
\---[g1 ]-------[h4 ]-------[i6 ]
| \---------------------------[j10]
\---[k3 ]
--d0----d1----d3----d4----d5----d6----d8----d9----d10-- => guide line (not rendered)
Возможно, будет проще попытаться создать этот, а не тот, который я опубликовал ранее.Во-первых, он сохраняет красивую форму сетки, и вам не нужно колебаться с диагональными линиями.Все строки отображаются вдоль четко видимых линий столбцов.К сожалению, он далеко не так хорош, как первый.