22
33# Default configuration constants
44DEFAULT_UNIT_SIZE = 3
5- DEFAULT_VALUE_FILL_CHAR = " " # Character used to pad node values (e.g., "_5_")
5+ DEFAULT_VALUE_FILL_CHAR = "_ " # Character used to pad node values (e.g., "_5_")
66DEFAULT_CONNECTOR_FILL_CHAR = "_" # Character used to fill horizontal gaps between node pairs
77
88
@@ -31,7 +31,6 @@ class BinaryNode:
3131 >>> # 4 5 7
3232 """
3333 def __init__ (self , val = 0 , left = None , right = None ):
34- # If val is a list, build tree from it
3534 if isinstance (val , list ):
3635 if not val or val [0 ] is None :
3736 raise ValueError ("Cannot create tree from empty list or list starting with None" )
@@ -46,13 +45,11 @@ def __init__(self, val=0, left=None, right=None):
4645 while queue and i < len (val ):
4746 node = queue .pop (0 )
4847
49- # Add left child
5048 if i < len (val ) and val [i ] is not None :
5149 node .left = BinaryNode (val [i ])
5250 queue .append (node .left )
5351 i += 1
5452
55- # Add right child
5653 if i < len (val ) and val [i ] is not None :
5754 node .right = BinaryNode (val [i ])
5855 queue .append (node .right )
@@ -106,13 +103,13 @@ def mapNodesToCodes(node, valueFillChar, unitSize, code="", memo=None):
106103 return memo
107104
108105
109- def nodeToMat (node : BinaryNode , depth = - 1 , valueFillChar = None , connectorFillChar = None , unitSize = None , removeEmpty = True ):
106+ def nodeToMat (node : BinaryNode , depth = - 1 , valueFillChar = None , connectorFillChar = None , unitSize = None , removeEmpty = True , connectors = "/ \\ " ):
110107 """
111108 Converts a binary tree into a 2D matrix representation for visualization.
112109
113110 The matrix includes:
114111 - Even rows (0, 2, 4...): Node values
115- - Odd rows (1, 3, 5...): Connection lines (/ and \\ )
112+ - Odd rows (1, 3, 5...): Connection lines (using connectors )
116113
117114 Args:
118115 node: The root node of the tree to visualize
@@ -121,6 +118,7 @@ def nodeToMat(node: BinaryNode, depth=-1, valueFillChar=None, connectorFillChar=
121118 connectorFillChar: Character for filling horizontal gaps between node pairs
122119 unitSize: Size for centering values
123120 removeEmpty: Whether to remove empty leading columns
121+ connectors: Two-character string for connectors (e.g., "/\\ " or "||"), None to skip connector rows
124122 """
125123 if unitSize is None :
126124 unitSize = DEFAULT_UNIT_SIZE
@@ -129,66 +127,56 @@ def nodeToMat(node: BinaryNode, depth=-1, valueFillChar=None, connectorFillChar=
129127 if connectorFillChar is None :
130128 connectorFillChar = DEFAULT_CONNECTOR_FILL_CHAR
131129
130+ if connectors is not None and len (connectors ) != 2 :
131+ connectors = "/\\ "
132+
132133 if depth == - 1 :
133134 depth = getDepth (node )
134135
135- # Map all nodes to their binary path codes
136136 tree = mapNodesToCodes (node , valueFillChar , unitSize )
137137
138- # Cache frequently used values
139- numCols = 2 ** depth - 1 # Number of leaf positions (columns)
140- numRows = 2 * depth - 1 # Total rows (values + connectors)
138+ numCols = 2 ** depth - 1
139+ numRows = 2 * depth - 1
141140
142- # Initialize matrix with space-centered empty cells
143141 mat = [[center ("" , unitSize = unitSize , fillChar = " " ) for _ in range (numCols )] for _ in range (numRows )]
144142
145- # Start with all even column indices (where values can be placed)
146143 valueIndexes = [i for i in range (numCols ) if i % 2 == 0 ]
147144 prevValueIndexes = None
148145
149- # Build matrix from bottom to top
150146 for level in range (numRows - 1 , - 1 , - 1 ):
151- # Odd levels: place connection characters (/ and \)
152147 if level % 2 != 0 :
153- for i , index in enumerate (valueIndexes ):
154- mat [level ][index ] = [center ("/" , unitSize = unitSize , fillChar = " " ),
155- center ("\\ " , unitSize = unitSize , fillChar = " " )][i % 2 ]
148+ if connectors is not None :
149+ for i , index in enumerate (valueIndexes ):
150+ mat [level ][index ] = [center (connectors [0 ], unitSize = unitSize , fillChar = " " ),
151+ center (connectors [1 ], unitSize = unitSize , fillChar = " " )][i % 2 ]
156152
157- # Calculate parent positions (midpoints between child pairs)
158153 nextValueIndexes = []
159154 for i in range (0 , len (valueIndexes ) - 1 , 2 ):
160155 nextValueIndexes .append ((valueIndexes [i ] + valueIndexes [i + 1 ]) // 2 )
161156 valueIndexes = nextValueIndexes
162157 continue
163158
164- # Even levels: place node values
165- # Generate all binary codes for current level
166159 codes = list (product (* ["01" for _ in range (level // 2 )]))
167160 codes = ["" .join (code ) for code in codes ]
168161
169162 for i , index in enumerate (valueIndexes ):
170163 if codes [i ] in tree :
171164 mat [level ][index ] = tree [codes [i ]]
172165
173- # Fill horizontal gaps between node pairs using connectorFillChar
174166 if prevValueIndexes is not None :
175167 for i in range (0 , len (prevValueIndexes ), 2 ):
176168 if i + 1 < len (prevValueIndexes ):
177- # Calculate parent position (should not be overwritten)
178169 parentCol = (prevValueIndexes [i ] + prevValueIndexes [i + 1 ]) // 2
179- # Fill columns between children, except parent position
180170 for col in range (prevValueIndexes [i ] + 1 , prevValueIndexes [i + 1 ]):
181171 if col != parentCol :
182172 mat [level ][col ] = center ("" , unitSize = unitSize , fillChar = connectorFillChar )
183173
184- # Save current valueIndexes for next even level
185174 prevValueIndexes = valueIndexes
186175
187- # Remove empty leading columns if requested
188176 if removeEmpty :
189177 centeredSpace = center ("" , unitSize = unitSize , fillChar = " " )
190- centeredSlash = center ("/" , unitSize = unitSize , fillChar = " " )
191- centeredBackslash = center ("\\ " , unitSize = unitSize , fillChar = " " )
178+ centeredSlash = center (connectors [ 0 ] if connectors else "/" , unitSize = unitSize , fillChar = " " )
179+ centeredBackslash = center (connectors [ 1 ] if connectors else "\\ " , unitSize = unitSize , fillChar = " " )
192180
193181 for i in range (numCols ):
194182 remove = all (
@@ -203,7 +191,7 @@ def nodeToMat(node: BinaryNode, depth=-1, valueFillChar=None, connectorFillChar=
203191 return mat
204192
205193
206- def nodeToString (node : BinaryNode , depth = - 1 , valueFillChar = None , connectorFillChar = None , unitSize = None , removeEmpty = True , showConnectors = True ):
194+ def nodeToString (node : BinaryNode , depth = - 1 , valueFillChar = None , connectorFillChar = None , unitSize = None , removeEmpty = True , connectors = "/ \\ " ):
207195 """
208196 Converts a binary tree into a string representation for visualization.
209197
@@ -214,13 +202,13 @@ def nodeToString(node: BinaryNode, depth=-1, valueFillChar=None, connectorFillCh
214202 connectorFillChar: Character for filling horizontal gaps between node pairs
215203 unitSize: Size for centering values
216204 removeEmpty: Whether to remove empty leading columns
217- showConnectors: Whether to show connector lines (/ and \) between nodes
205+ connectors: Two-character string for connectors (e.g., "/ \\ " or "||"), None to skip connector rows
218206 """
219207 mat = nodeToMat (node , depth = depth , valueFillChar = valueFillChar ,
220- connectorFillChar = connectorFillChar , unitSize = unitSize , removeEmpty = removeEmpty )
208+ connectorFillChar = connectorFillChar , unitSize = unitSize ,
209+ removeEmpty = removeEmpty , connectors = connectors )
221210
222- if showConnectors :
211+ if connectors is not None :
223212 return "\n " .join ("" .join (row ) for row in mat )
224213 else :
225- # Only include even rows (node values, skip odd rows with connectors)
226214 return "\n " .join ("" .join (mat [i ]) for i in range (0 , len (mat ), 2 ))
0 commit comments