Есть ли способ получить простую ascii-визуализацию бинарного дерева поиска?

Я разработал двоичную структуру дерева поиска и хочу добавить некоторую функцию, которая может визуализировать дерево. Код ниже принадлежит двоичному дереву поиска:

class Node(object):
    def __init__(self, data):
        self.data = data
        self.leftChild = None
        self.rightChild = None

    def insert(self, data):
        if data < self.data:
            if not self.leftChild:
                self.leftChild = Node(data)
                return True
            else:
                self.leftChild.insert(data)
        else:
            if not self.rightChild:
               self.rightChild = Node(data)
               return True
            else:
               self.rightChild.insert(data)
    def inOrder(self):
        """
        Traversing the tree in inorder form (LVR).

        """
        if self:
            if self.leftChild:
               self.leftChild.inOrder()
            print(self.data)
            if self.rightChild:
                self.rightChild.inOrder()
class BST(object):
    def __init__(self):
        self.rootNode = None

    def insert(self, data):
        if not self.rootNode:
            self.rootNode = Node(data)
        else:
            self.rootNode.insert(data)
    def inOrder(self):
        self.rootNode.inOrder()

вы можете протестировать код, чтобы увидеть, как он рекурсивно обходит дерево:

bst = BST()

bst.insert(12)
bst.insert(14)
bst.insert(8)
bst.insert(11)
bst.insert(7)
bst.inOrder()

Для визуализации я использовал библиотеку ete. В библиотеке ete3, если вы используете код ниже:

from ete3 import Tree
# Loads a tree. Note that we use format 1 to read internal node names
tree_format = '(((J)H,K)D,((S,E)A,(T)B)C)F;'
t = Tree(tree_format, format=1)
print( t.get_ascii())

вы получите такой вывод:

      /H /-J
   /D|
  |   \-K
-F|
  |      /-S
  |   /A|
   \C|   \-E
     |
      \B /-T

Как вы можете видеть в приведенном выше коде, если бы я мог создать переменную tree_format из структуры BST, тогда я смог бы получить визуальное представление дерева.
Чтобы сделать это, программа должна < br/> 1. Обход дерева в формате RLV.
2. во время обхода он должен использовать () , , и ;.
Может ли кто-нибудь помочь мне завершить код.
Если кто-нибудь есть более простой способ визуализации BST, я был бы очень благодарен увидеть.
Спасибо, ребята.


person Masoud Masoumi Moghadam    schedule 21.09.2016    source источник
comment
Похоже, если вы сделаете обратный обход в обратном порядке, отслеживая глубину, у вас все получится. Когда глубина увеличивается, вы добавляете левую скобку. Вы добавляете запятую между узлами на той же глубине, а когда глубина уменьшается, вы добавляете правую круглую скобку.   -  person Jim Mischel    schedule 22.09.2016
comment
Кажется, что если я использую нерекурсивный режим для обхода, я могу получить ключ к решению проблемы.   -  person Masoud Masoumi Moghadam    schedule 23.09.2016


Ответы (3)


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

Вот некоторый код на C#, который вы сможете достаточно легко перенести на Python:

string Traverse(Node node)
{
    string rslt = "";
    bool hasRightNode = false;
    bool hasLeftNode = false;
    if (node.Right != null)
    {
        hasRightNode = true;
        rslt = rslt + "(";
        rslt = rslt + Traverse(node.Right);
    }
    if (node.Left != null)
    {
        hasLeftNode = true;
        if (hasRightNode)
        {
            rslt = rslt + ",";
        }
        else
        {
            rslt = rslt + "(";
        }
        rslt = rslt + Traverse(node.Left);
    }
    if (hasLeftNode || hasRightNode)
    {
        rslt = rslt + ")";
    }
    rslt = rslt + node.Value;
    return rslt;
}

Не хватает только последней точки с запятой. Вы можете вызвать его с помощью:

string format = Traverse(root) + ";";

Учитывая опубликованное вами дерево, оно выводит ожидаемую строку формата.

Обратите внимание, что здесь я использую конкатенацию строк, которая неоптимальна в C#. Если бы это была производственная программа, я бы, вероятно, использовал объект StringBuilder, чтобы избежать конкатенации. Я недостаточно знаком с Python, чтобы сказать, как лучше составлять строки на этом языке.

person Jim Mischel    schedule 23.09.2016
comment
Большое спасибо. это конечно очень помогает - person Masoud Masoumi Moghadam; 23.09.2016
comment
@MasoudMasoumiMoghadam: Если мой ответ решил вашу проблему, отметьте его как принятый ответ. - person Jim Mischel; 23.09.2016

Согласно образцу кода мистера Джима Мишеля на C#, я добавил следующую функцию в класс Node:

def R_postorder(self):
    ret = ''
    if self:
        hasRightChild = False
        hasLeftChild = False
        if self.rightChild:
            hasRightChild = True
            ret += '('
            ret += self.rightChild.RLV()

        if self.leftChild:
            hasLeftChild = True
            if hasRightChild:
                ret += ','
            else:
                ret += '('
            ret += self.leftChild.RLV()
        if hasRightChild or hasLeftChild:
            ret += ')'
        ret += str(self.data)
    return ret

и я также добавил R_postorder в класс BST:

def R_postorder(self):
    ret = self.rootNode.RLV()
    ret += ';'
    return ret

Используя возвращаемое значение bst.R_postorder() в качестве входных данных для создания переменной tree_format, будет достигнут правильный результат.

person Masoud Masoumi Moghadam    schedule 23.09.2016
comment
Это не очень дружелюбно — просить о помощи, а затем не отдавать должное человеку, который дает вам ответ. Пометка собственного сообщения как принятого ответа лишает человека, который фактически решил вашу проблему, получения баллов за нее. Лично меня не особо волнуют несколько пунктов, потому что у меня их много, а у других есть, и вы можете обнаружить, что люди не захотят вам помочь. - person Jim Mischel; 01.10.2016
comment
Мне жаль, мой друг. Я не имел в виду это. Я думал, что правильный ответ - это тот, на который отвечают, используя python, а не C #. поэтому я не отметил ваш код. Вы должны знать, что это было недоразумение и ничего преднамеренного. Потому что, как видите, я оценил вашу помощь, а также упомянул ваше имя в своем ответе. Пожалуйста, не обращайте на это внимания. Я еще не профессионал, как вы - person Masoud Masoumi Moghadam; 02.10.2016
comment
Не проблема. Просто дружеское напоминание. Добро пожаловать в Stack Overflow. - person Jim Mischel; 02.10.2016

  1. Вам нужно будет пройти по порядку уровней по вашему дереву.
  2. Выберите длину узла и длину пробела.
  3. Получите базовую ширину дерева относительно каждого уровня, который равен node_length * nodes_count + space_length * spaces_count*.
  4. Найдите связь между ветвлением, расстоянием, отступом и расчетной шириной основания.

Код на GitHub: ЮсефРаафатНасри/bst-ascii-visualization

                                             07                     
                                             /\                     
                                            /  \                    
                                           /    \                   
                                          /      \                  
                                         /        \                 
                                        /          \                
                                       /            \               
                                      /              \              
                                     /                \             
                                    /                  \            
                                   /                    \           
                                 03                      11         
                                 /\                      /\         
                                /  \                    /  \        
                               /    \                  /    \       
                              /      \                /      \      
                             /        \              /        \     
                           01          05          09          13   
                           /\          /\          /\          /\   
                          /  \        /  \        /  \        /  \  
                        00    02    04    06    08    10    12    14
person YoussefRaafatNasry    schedule 19.07.2019