Ich habe mit dem folgenden Verfahren beendet, die Sie beliebige Teilstruktur drucken:
public static class BTreePrinter
{
class NodeInfo
{
public BNode Node;
public string Text;
public int StartPos;
public int Size { get { return Text.Length; } }
public int EndPos { get { return StartPos + Size; } set { StartPos = value - Size; } }
public NodeInfo Parent, Left, Right;
}
public static void Print(this BNode root, string textFormat = "0", int spacing = 1, int topMargin = 2, int leftMargin = 2)
{
if (root == null) return;
int rootTop = Console.CursorTop + topMargin;
var last = new List<NodeInfo>();
var next = root;
for (int level = 0; next != null; level++)
{
var item = new NodeInfo { Node = next, Text = next.item.ToString(textFormat) };
if (level < last.Count)
{
item.StartPos = last[level].EndPos + spacing;
last[level] = item;
}
else
{
item.StartPos = leftMargin;
last.Add(item);
}
if (level > 0)
{
item.Parent = last[level - 1];
if (next == item.Parent.Node.left)
{
item.Parent.Left = item;
item.EndPos = Math.Max(item.EndPos, item.Parent.StartPos - 1);
}
else
{
item.Parent.Right = item;
item.StartPos = Math.Max(item.StartPos, item.Parent.EndPos + 1);
}
}
next = next.left ?? next.right;
for (; next == null; item = item.Parent)
{
int top = rootTop + 2 * level;
Print(item.Text, top, item.StartPos);
if (item.Left != null)
{
Print("/", top + 1, item.Left.EndPos);
Print("_", top, item.Left.EndPos + 1, item.StartPos);
}
if (item.Right != null)
{
Print("_", top, item.EndPos, item.Right.StartPos - 1);
Print("\\", top + 1, item.Right.StartPos - 1);
}
if (--level < 0) break;
if (item == item.Parent.Left)
{
item.Parent.StartPos = item.EndPos + 1;
next = item.Parent.Node.right;
}
else
{
if (item.Parent.Left == null)
item.Parent.EndPos = item.StartPos - 1;
else
item.Parent.StartPos += (item.StartPos - 1 - item.Parent.EndPos)/2;
}
}
}
Console.SetCursorPosition(0, rootTop + 2 * last.Count - 1);
}
private static void Print(string s, int top, int left, int right = -1)
{
Console.SetCursorPosition(left, top);
if (right < 0) right = left + s.Length;
while (Console.CursorLeft < right) Console.Write(s);
}
}
Wie Sie sehen können, ich Es wurden einige Parameter hinzugefügt, die sich auf die Formatierung auswirken. Standardmäßig erzeugt es die kompakteste Darstellung.
Um mit ihm zu spielen, ich habe die BTree
Klasse geändert haben, wie folgt:
public class BTree
{
// ...
public BNode Root { get { return _root; } }
public void Print()
{
Root.Print();
}
}
Ihre Beispieldaten verwenden, sind hier einige Ergebnisse:
btr.Root.Print();
btr.Root.Print(textFormat: "(0)", spacing: 2);
UPDATE: IMO das Standardformat oben ist kompakt und lesbar, aber nur zum Spaß, angepasst, um den Algorithmus mehr "grafischen" -Ausgang (textFormat
und spacing
Parameter entfernt) zu erzeugen:
public static class BTreePrinter
{
class NodeInfo
{
public BNode Node;
public string Text;
public int StartPos;
public int Size { get { return Text.Length; } }
public int EndPos { get { return StartPos + Size; } set { StartPos = value - Size; } }
public NodeInfo Parent, Left, Right;
}
public static void Print(this BNode root, int topMargin = 2, int leftMargin = 2)
{
if (root == null) return;
int rootTop = Console.CursorTop + topMargin;
var last = new List<NodeInfo>();
var next = root;
for (int level = 0; next != null; level++)
{
var item = new NodeInfo { Node = next, Text = next.item.ToString(" 0 ") };
if (level < last.Count)
{
item.StartPos = last[level].EndPos + 1;
last[level] = item;
}
else
{
item.StartPos = leftMargin;
last.Add(item);
}
if (level > 0)
{
item.Parent = last[level - 1];
if (next == item.Parent.Node.left)
{
item.Parent.Left = item;
item.EndPos = Math.Max(item.EndPos, item.Parent.StartPos);
}
else
{
item.Parent.Right = item;
item.StartPos = Math.Max(item.StartPos, item.Parent.EndPos);
}
}
next = next.left ?? next.right;
for (; next == null; item = item.Parent)
{
Print(item, rootTop + 2 * level);
if (--level < 0) break;
if (item == item.Parent.Left)
{
item.Parent.StartPos = item.EndPos;
next = item.Parent.Node.right;
}
else
{
if (item.Parent.Left == null)
item.Parent.EndPos = item.StartPos;
else
item.Parent.StartPos += (item.StartPos - item.Parent.EndPos)/2;
}
}
}
Console.SetCursorPosition(0, rootTop + 2 * last.Count - 1);
}
private static void Print(NodeInfo item, int top)
{
SwapColors();
Print(item.Text, top, item.StartPos);
SwapColors();
if (item.Left != null)
PrintLink(top + 1, "┌", "┘", item.Left.StartPos + item.Left.Size/2, item.StartPos);
if (item.Right != null)
PrintLink(top + 1, "└", "┐", item.EndPos - 1, item.Right.StartPos + item.Right.Size/2);
}
private static void PrintLink(int top, string start, string end, int startPos, int endPos)
{
Print(start, top, startPos);
Print("─", top, startPos + 1, endPos);
Print(end, top, endPos);
}
private static void Print(string s, int top, int left, int right = -1)
{
Console.SetCursorPosition(left, top);
if (right < 0) right = left + s.Length;
while (Console.CursorLeft < right) Console.Write(s);
}
private static void SwapColors()
{
var color = Console.ForegroundColor;
Console.ForegroundColor = Console.BackgroundColor;
Console.BackgroundColor = color;
}
}
und das Ergebnis ist:
ich denke, der Ansatz in diesem anderen Link schöner aussieht und kompakter: http://StackOverflow.com/a/1649223/831138. "Kompakt" in dem Sinne, dass man mehr Informationen auf demselben Bildschirm platzieren kann ... natürlich wird es vertikal gestreckt, aber die Verwendung der Bildlaufleiste der Konsole sollte kein Problem sein ... aus der Horizontalen herauslaufen Platz ist ein Problem. –
Mögliches Duplikat von [Baumvisualisierungsalgorithmus] (http://stackoverflow.com/questions/8368386/tree-visualization-algorithm) – mbeckish
http://stackoverflow.com/questions/801740/c-how-to-draw-a -binary-Baum-zur-Konsole – fubo