Hier einige Code, der den allgemeinen, rekursive Ansatz an anderer Stelle beschrieben implementiert. Die interne Repräsentation eines Baumes ist entweder eine Zeichenkette (Blatt) oder ein Tupel (Paar) von Unterknoten. Die interne Darstellung des intermediären "Fragments" eines Knotens ist das Tupel (above, below, lines)
, wobei above
und below
die Anzahl der Zeilen über und unter der Wurzel sind und lines
ein Iterator über jede Teilzeile ist (ohne Leerzeichen auf der linken Seite).
#!/usr/local/bin/python3.3
from itertools import chain
from random import randint
def leaf(t):
return isinstance(t, str)
def random(n):
def extend(t):
if leaf(t):
return (t+'l', t+'r')
else:
l, r = t
if randint(0, 1): return (l, extend(r))
else: return (extend(l), r)
t = ''
for _ in range(n-1): t = extend(t)
return t
def format(t):
def pad(prefix, spaces, previous):
return prefix + (' ' * spaces) + previous
def merge(l, r):
l_above, l_below, l_lines = l
r_above, r_below, r_lines = r
gap = r_below + l_above
gap_above = l_above
gap_below = gap - gap_above
def lines():
for (i, line) in enumerate(chain(r_lines, l_lines)):
if i < r_above:
yield ' ' + line
elif i - r_above < gap_above:
dash = '_' if i - r_above == gap_above - 1 else ' '
if i < r_above + r_below:
yield pad(dash + '/', 2 * (i - r_above), line)
else:
yield pad(dash + '/', 2 * gap_below - 1, line)
elif i - r_above - gap_above < gap_below:
if i < r_above + r_below:
yield pad(' \\', 2 * gap_above - 1, line)
else:
spaces = 2 * (r_above + gap_above + gap_below - i - 1)
yield pad(' \\', spaces, line)
else:
yield ' ' + line
return (r_above + gap_above, gap_below + l_below, lines())
def descend(left, t):
if leaf(t):
if left:
return (1, 0, [t])
else:
return (0, 1, [t])
else:
l, r = t
return merge(descend(True, l), descend(False, r))
def flatten(t):
above, below, lines = t
for (i, line) in enumerate(lines):
if i < above: yield (' ' * (above - i - 1)) + line
else: yield (' ' * (i - above)) + line
return '\n'.join(flatten(descend(True, t)))
if __name__ == '__main__':
for n in range(1,20,3):
tree = random(n)
print(format(tree))
Hier ist ein Beispiel einer Ausgabe:
_/rrrr
_/ \_/rrrlr
/\ \rrrll
_/ \_/rrlr
/\ \rrll
/ \ _/rlrr
/ \_/ \rlrl
_/ \_/rllr
\ \_/rlllr
\ \rllll
\ _/lrrr
\ _/ \lrrl
\ /\_/lrlr
\_/ \lrll
\ _/llrr
\_/ \llrl
\_/lllr
\_/llllr
\lllll
Und ein bisschen mehr asymmetrische eine, vielleicht zeigt, warum ich mit Leerzeichen nach links bis zum Ende (über flatten
) nicht Pad Linien tun. Wäre die untere Hälfte links gepolstert worden, würde ein Teil des Oberarms den Polsterbereich durchqueren.
Es ist der "offensichtliche" rekursive Algorithmus - der Teufel steckt im Detail. Es war am einfachsten ohne das "_" zu schreiben, was die Logik etwas komplexer macht.
Vielleicht ist die einzige "Einsicht" gap_above = l_above
- das heißt, dass der rechte "Arm" die Länge der rechten Seite des linken Teilbaums hat (Sie müssen das ein paar Mal lesen). Es macht die Dinge relativ ausgeglichen. Siehe das obige asymmetrische Beispiel.
Eine gute Möglichkeit, Dinge genauer zu verstehen, ist die Routine zu ändern, um ein Zeichen anstelle von ' '
zu nehmen und ein anderes Zeichen für jeden Anruf zu geben. Dann können Sie genau sehen, welche Logik welchen Raum erzeugt hat. Dies ist, was Sie für die Anrufe zu Pad von oben nach unten mit A, B, C und D erhalten, über (natürlich kein Zeichen gibt es, wenn die Menge an Speicherplatz Null ist):
_/rrrr
/\rrrl
_/B _/rrlrr
/\_/ \rrlrl
/AA \rrll
_/BBB _/rlrrr
/\DD _/ \rlrrl
/AA \_/ \_/rlrlr
/AAAA \C \rlrll
/AAAAAA \_/rllr
_/AAAAAAAA \rlll
\DDDDDDDD _/lrrrr
\DDDDDD _/ \lrrrl
\DDDD/\lrrl
\DD _/B _/lrlrr
\_/ \_/ \lrlrl
\C \lrll
\_/llr
\lll
Es gibt mehr Erklärung here (obwohl der Baum sehr leicht anders ist).
Was hast du probiert? Ich kann mir vorstellen, dass es die Berechnung der Eigenschaften des Baumes (Tiefe, Breite usw.), die Berechnung des Layouts und die Erzeugung der ASCII-Kunst beinhaltet. –
@SimeonVisser hat einen defekten Code hinzugefügt – Will
Wenn ich das ansehe, denke ich, dass Sie auch die Baumtiefe verfolgen sollten. Ich habe einen rudimentären Code, der auf deinem kaputten Code basiert, aber er sieht schrecklich aus. Für jede Zeile versuche ich herauszufinden, wie viel zusätzlichen Platz es haben sollte, aber die Rekonstruktion für diese Zeile ist derzeit nur für den niedrigsten Zweig verantwortlich. – Michael