Кодирование простого симпатичного принтера для деревьев в Java - PullRequest
1 голос
/ 23 января 2012

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

Я знаю, что первый шаг - сделать предзаказ, чтобы получить все узлы.

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

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

Нет кода, просто спрашиваю идеи о том, как другие будут это делать.

И, может быть, потом код, если я в отчаянии: P

Чтобы быть конкретным, это должно выглядеть так:

example

Ответы [ 3 ]

9 голосов
/ 23 января 2012

Если вы знаете глубину дерева, то есть количество уровней , вы можете рассчитать максимальное количество узлов на последнем уровне (которое равно n 2 для n = количество уровней - 1, 1 элемент, если у вас есть только рут). Если вы также знаете ширину элементов (например, если у вас не более двухзначных чисел, каждый элемент будет иметь ширину 2), вы можете рассчитать ширину последнего уровня: ((number of elements - 1) * (element width + spacing) + element width).

На самом деле вышеприведенный абзац не имеет значения. Все, что вам нужно, это глубина дерева, то есть максимальный уровень, который должен отображаться. Однако, если дерево разреженное, то есть присутствуют не все элементы последнего уровня и, возможно, выше, вам необходимо получить позицию отображаемого узла, чтобы соответствующим образом адаптировать отступ / интервал для этого случая.

В ходе итерации предварительного заказа вы можете рассчитать отступы и интервалы между элементами на каждом уровне. Формула для отступа будет выглядеть следующим образом: 2 (максимальный уровень - уровень) - 1 и интервал: 2 (максимальный уровень - уровень + 1) - 1 (уровень основан на 1)

Пример:

       1
   2       3
 4   5   6   7
8 9 A B C D E F

В этом дереве количество уровней равно 4. Интервал на последнем уровне равен 1, тогда как отступ равен 0. Вы получите следующие значения:

  • уровень 1:
    • indent = 7: (2 (4-1) - 1 = 2 3 - 1 = 8 - 1 = 7)
    • первый уровень, поэтому расстояние не имеет значения
  • уровень 2:
    • indent = 3: (2 (4-2) - 1 = 2 2 - 1 = 4 - 1 = 3)
    • spacing = 7 (2 (4-1) - 1 = 2 3 - 1 = 8 - 1 = 7)
  • уровень 3:
    • indent = 1: (2 (4-3) - 1 = 2 1 - 1 = 2 - 1 = 1)
    • spacing = 3 (2 (4-2) - 1 = 2 2 - 1 = 4 - 1 = 3)
  • уровень 4:
    • indent = 0: (2 (4-4) - 1 = 2 0 - 1 = 1 - 1 = 0)
    • spacing = 1: (2 (4-3) - 1 = 2 1 - 1 = 2 - 1 = 1)

Обратите внимание, что на последнем уровне у вас всегда будет интервал 1 * ширины элемента. Таким образом, для максимальной ширины элемента 3 (например, 3-значных чисел) у вас будет интервал 3 на последнем уровне, чтобы получить некоторое выравнивание верхних уровней.

Редактировать : Для вашего красивого отпечатка вам просто нужно рассчитать отступ как width element * level, где уровень будет начинаться с нуля. Затем, если узел не является листом, нарисуйте его с открывающим паратезом впереди и закрывающим парантезом после рисования потомков, если это лист, просто нарисуйте его, а если лист отсутствует, нарисуйте двойной парантхис.

Таким образом, вы получите что-то вроде этого:

public void printSubtree( int indent, node ) {
  for( int i = 0; i < indent; ++i) {
    System.out.print(" ");
  }

  if( inner node) {
    System.out.println("(" + value);     
    printSubtree(indent + elem width, left child); //this is a recursive call, alternatively use the indent formula above if you don't use recursion
    printSubtree(indent + elem width, right child);

    //we have a new line so print the indent again
    for( int i = 0; i < indent; ++i) {
      System.out.print(" ");
    }
    System.out.println(")"); 
  } else if( not empty) {
    System.out.println(value);
  } else { //empty/non existing node
    System.out.println("()");
  }
}
5 голосов
/ 18 сентября 2017

Работает для всех входов и печатает строку для связи, как показано на рисунке ниже enter image description here

package com.sai.samples;

/**
 * @author Saiteja Tokala
 */
import java.util.ArrayList;
import java.util.List;


/**
 * Binary tree printer
 *
 * @author saiteja
 */
public class TreePrinter
{
    /** Node that can be printed */
    public interface PrintableNode
    {
        /** Get left child */
        PrintableNode getLeft();


        /** Get right child */
        PrintableNode getRight();


        /** Get text to be printed */
        String getText();
    }


    /**
     * Print a tree
     *
     * @param root
     *            tree root node
     */
    public static void print(PrintableNode root)
    {
        List<List<String>> lines = new ArrayList<List<String>>();

        List<PrintableNode> level = new ArrayList<PrintableNode>();
        List<PrintableNode> next = new ArrayList<PrintableNode>();

        level.add(root);
        int nn = 1;

        int widest = 0;

        while (nn != 0) {
            List<String> line = new ArrayList<String>();

            nn = 0;

            for (PrintableNode n : level) {
                if (n == null) {
                    line.add(null);

                    next.add(null);
                    next.add(null);
                } else {
                    String aa = n.getText();
                    line.add(aa);
                    if (aa.length() > widest) widest = aa.length();

                    next.add(n.getLeft());
                    next.add(n.getRight());

                    if (n.getLeft() != null) nn++;
                    if (n.getRight() != null) nn++;
                }
            }

            if (widest % 2 == 1) widest++;

            lines.add(line);

            List<PrintableNode> tmp = level;
            level = next;
            next = tmp;
            next.clear();
        }

        int perpiece = lines.get(lines.size() - 1).size() * (widest + 4);
        for (int i = 0; i < lines.size(); i++) {
            List<String> line = lines.get(i);
            int hpw = (int) Math.floor(perpiece / 2f) - 1;

            if (i > 0) {
                for (int j = 0; j < line.size(); j++) {

                    // split node
                    char c = ' ';
                    if (j % 2 == 1) {
                        if (line.get(j - 1) != null) {
                            c = (line.get(j) != null) ? '┴' : '┘';
                        } else {
                            if (j < line.size() && line.get(j) != null) c = '└';
                        }
                    }
                    System.out.print(c);

                    // lines and spaces
                    if (line.get(j) == null) {
                        for (int k = 0; k < perpiece - 1; k++) {
                            System.out.print(" ");
                        }
                    } else {

                        for (int k = 0; k < hpw; k++) {
                            System.out.print(j % 2 == 0 ? " " : "─");
                        }
                        System.out.print(j % 2 == 0 ? "┌" : "┐");
                        for (int k = 0; k < hpw; k++) {
                            System.out.print(j % 2 == 0 ? "─" : " ");
                        }
                    }
                }
                System.out.println();
            }

            // print line of numbers
            for (int j = 0; j < line.size(); j++) {

                String f = line.get(j);
                if (f == null) f = "";
                int gap1 = (int) Math.ceil(perpiece / 2f - f.length() / 2f);
                int gap2 = (int) Math.floor(perpiece / 2f - f.length() / 2f);

                // a number
                for (int k = 0; k < gap1; k++) {
                    System.out.print(" ");
                }
                System.out.print(f);
                for (int k = 0; k < gap2; k++) {
                    System.out.print(" ");
                }
            }
            System.out.println();

            perpiece /= 2;
        }
    }
}
1 голос
/ 23 января 2012

Поскольку функция обхода является рекурсивной, вы можете передавать аргументы форматирования (например, количество пробелов для отступа каждого узла) в рекурсивных вызовах.Например, если вы хотите сделать отступ в 2 пробела для каждого уровня в дереве, вы можете запустить рекурсию с аргументом 0, а затем добавить 2 на каждом рекурсивном шаге.

...