22
33# Default configuration constants
44DEFAULT_UNIT_SIZE = 3
5- DEFAULT_VALUE_FILL_CHAR = "_"
6- DEFAULT_GAP_FILL_CHAR = "_"
5+ DEFAULT_VALUE_FILL_CHAR = "_" # Character used to pad node values (e.g., "_5_")
6+ DEFAULT_CONNECTOR_FILL_CHAR = "_" # Character used to fill horizontal gaps between node pairs
77
88
99class BinaryNode :
@@ -17,11 +17,6 @@ class BinaryNode:
1717 left: Reference to the left child node (only used when val is not a list)
1818 right: Reference to the right child node (only used when val is not a list)
1919
20- Attributes:
21- val: The value stored in the node
22- left: Reference to the left child node
23- right: Reference to the right child node
24-
2520 Example:
2621 >>> # Create a single node
2722 >>> node = BinaryNode(5)
@@ -73,18 +68,9 @@ def __str__(self):
7368 def __repr__ (self ):
7469 return str (self )
7570
71+
7672def center (val , unitSize = None , fillChar = None ):
77- """
78- Centers a value within a fixed width string.
79-
80- Args:
81- val: The value to center
82- unitSize: The total width of the output string (uses DEFAULT_UNIT_SIZE if None)
83- fillChar: The character to use for padding (uses DEFAULT_VALUE_FILL_CHAR "_" if None)
84-
85- Returns:
86- A centered string representation of val
87- """
73+ """Centers a value within a fixed width string."""
8874 if unitSize is None :
8975 unitSize = DEFAULT_UNIT_SIZE
9076 if fillChar is None :
@@ -93,46 +79,34 @@ def center(val, unitSize=None, fillChar=None):
9379
9480
9581def getDepth (node : BinaryNode ):
96- """
97- Calculates the depth (height) of a binary tree.
98-
99- Args:
100- node: The root node of the tree
101-
102- Returns:
103- The depth of the tree (number of levels from root to deepest leaf)
104- """
105- if node == None :
82+ """Calculates the depth (height) of a binary tree."""
83+ if node is None :
10684 return 0
10785 return 1 + max (getDepth (node .left ), getDepth (node .right ))
10886
10987
110- def register (node : BinaryNode , valueFillChar = None , unitSize = None , code = "" , mem = None ):
88+ def mapNodesToCodes (node : BinaryNode , valueFillChar , unitSize , code = "" , memo = None ):
11189 """
112- Recursively registers all nodes in a tree with their binary path codes.
90+ Recursively maps all nodes to their binary path codes.
11391
11492 Each node is assigned a binary code representing its position:
11593 - Empty string "" for root
11694 - "0" appended for left child
11795 - "1" appended for right child
11896
119- Args:
120- node: The current node being processed
121- valueFillChar: Character used for padding node values (uses DEFAULT_VALUE_FILL_CHAR "_" if None)
122- unitSize: Size for centering values (uses DEFAULT_UNIT_SIZE if None)
123- code: The binary path code for the current node
124- mem: Dictionary mapping binary codes to centered node values
97+ Returns:
98+ Dictionary mapping binary codes to centered node values
12599 """
126- if mem is None :
127- mem = {}
100+ if memo is None :
101+ memo = {}
128102 if node :
129- mem [code ] = center (node .val , unitSize = unitSize , fillChar = valueFillChar )
130- register (node .left , valueFillChar = valueFillChar , unitSize = unitSize , code = code + "0" , mem = mem )
131- register (node .right , valueFillChar = valueFillChar , unitSize = unitSize , code = code + "1" , mem = mem )
132- return mem
103+ memo [code ] = center (node .val , unitSize = unitSize , fillChar = valueFillChar )
104+ mapNodesToCodes (node .left , valueFillChar , unitSize , code + "0" , memo )
105+ mapNodesToCodes (node .right , valueFillChar , unitSize , code + "1" , memo )
106+ return memo
133107
134108
135- def nodeToMat (node : BinaryNode , depth = - 1 , valueFillChar = None , gapFillChar = None , unitSize = None , removeEmpty = True ):
109+ def nodeToMat (node : BinaryNode , depth = - 1 , valueFillChar = None , connectorFillChar = None , unitSize = None , removeEmpty = True ):
136110 """
137111 Converts a binary tree into a 2D matrix representation for visualization.
138112
@@ -143,47 +117,48 @@ def nodeToMat(node: BinaryNode, depth=-1, valueFillChar=None, gapFillChar=None,
143117 Args:
144118 node: The root node of the tree to visualize
145119 depth: The depth of the tree (-1 for auto-calculation)
146- valueFillChar: Character for padding node values (uses DEFAULT_VALUE_FILL_CHAR "_" if None )
147- gapFillChar : Character for filling gaps between pairs (uses DEFAULT_GAP_FILL_CHAR "_" if None)
148- unitSize: Size for centering (uses DEFAULT_UNIT_SIZE if None)
120+ valueFillChar: Character for padding node values (e.g., "_5_" )
121+ connectorFillChar : Character for filling horizontal gaps between node pairs
122+ unitSize: Size for centering values
149123 removeEmpty: Whether to remove empty leading columns
150-
151- Returns:
152- A 2D list (matrix) representing the tree structure
153124 """
154125 if unitSize is None :
155126 unitSize = DEFAULT_UNIT_SIZE
156127 if valueFillChar is None :
157128 valueFillChar = DEFAULT_VALUE_FILL_CHAR
158- if gapFillChar is None :
159- gapFillChar = DEFAULT_GAP_FILL_CHAR
129+ if connectorFillChar is None :
130+ connectorFillChar = DEFAULT_CONNECTOR_FILL_CHAR
160131
161132 if depth == - 1 :
162133 depth = getDepth (node )
163134
164- # Register all nodes with their binary path codes
165- tree = register (node , valueFillChar = valueFillChar , unitSize = unitSize , code = "" , mem = {})
135+ # Map all nodes to their binary path codes
136+ tree = mapNodesToCodes (node , valueFillChar , unitSize )
137+
138+ # Cache frequently used values
139+ numCols = 2 ** depth - 1 # Number of leaf positions (columns)
140+ numRows = 2 * depth - 1 # Total rows (values + connectors)
166141
167- # Create matrix: (2*depth - 1) rows x (2^depth - 1) columns
168- # Initialize with space-centered empty cells
169- mat = [[center ("" , unitSize = unitSize , fillChar = " " ) for _ in range (2 ** depth - 1 )] for _ in range (2 * depth - 1 )]
142+ # Initialize matrix with space-centered empty cells
143+ mat = [[center ("" , unitSize = unitSize , fillChar = " " ) for _ in range (numCols )] for _ in range (numRows )]
170144
171145 # Start with all even column indices (where values can be placed)
172- valueIndexes = [i for i in range (2 ** depth - 1 ) if i % 2 == 0 ]
173- prev = None
146+ valueIndexes = [i for i in range (numCols ) if i % 2 == 0 ]
147+ prevValueIndexes = None
174148
175149 # Build matrix from bottom to top
176- for level in range (2 * ( depth - 1 ) , - 1 , - 1 ):
150+ for level in range (numRows - 1 , - 1 , - 1 ):
177151 # Odd levels: place connection characters (/ and \)
178152 if level % 2 != 0 :
179153 for i , index in enumerate (valueIndexes ):
180- mat [level ][index ] = [center ("/" , unitSize = unitSize , fillChar = " " ), center ("\\ " , unitSize = unitSize , fillChar = " " )][i % 2 ]
154+ mat [level ][index ] = [center ("/" , unitSize = unitSize , fillChar = " " ),
155+ center ("\\ " , unitSize = unitSize , fillChar = " " )][i % 2 ]
181156
182157 # Calculate parent positions (midpoints between child pairs)
183- next = []
158+ nextValueIndexes = []
184159 for i in range (0 , len (valueIndexes ) - 1 , 2 ):
185- next .append ((valueIndexes [i ] + valueIndexes [i + 1 ]) // 2 )
186- valueIndexes = next
160+ nextValueIndexes .append ((valueIndexes [i ] + valueIndexes [i + 1 ]) // 2 )
161+ valueIndexes = nextValueIndexes
187162 continue
188163
189164 # Even levels: place node values
@@ -195,55 +170,51 @@ def nodeToMat(node: BinaryNode, depth=-1, valueFillChar=None, gapFillChar=None,
195170 if codes [i ] in tree :
196171 mat [level ][index ] = tree [codes [i ]]
197172
198- # Fill gaps between pairs using prev (previous even level's valueIndexes)
199- if prev is not None :
200- for i in range (0 , len (prev ), 2 ):
201- if i + 1 < len (prev ):
173+ # Fill horizontal gaps between node pairs using connectorFillChar
174+ if prevValueIndexes is not None :
175+ for i in range (0 , len (prevValueIndexes ), 2 ):
176+ if i + 1 < len (prevValueIndexes ):
202177 # Calculate parent position (should not be overwritten)
203- parent_col = (prev [i ] + prev [i + 1 ]) // 2
204- # Fill columns between prev[i] and prev[i+1] , except parent
205- for col in range (prev [i ] + 1 , prev [i + 1 ]):
206- if col != parent_col :
207- mat [level ][col ] = center ("" , unitSize = unitSize , fillChar = gapFillChar )
178+ parentCol = (prevValueIndexes [i ] + prevValueIndexes [i + 1 ]) // 2
179+ # Fill columns between children , except parent position
180+ for col in range (prevValueIndexes [i ] + 1 , prevValueIndexes [i + 1 ]):
181+ if col != parentCol :
182+ mat [level ][col ] = center ("" , unitSize = unitSize , fillChar = connectorFillChar )
208183
209184 # Save current valueIndexes for next even level
210- prev = valueIndexes
185+ prevValueIndexes = valueIndexes
211186
212187 # Remove empty leading columns if requested
213188 if removeEmpty :
214189 centeredSpace = center ("" , unitSize = unitSize , fillChar = " " )
215190 centeredSlash = center ("/" , unitSize = unitSize , fillChar = " " )
216191 centeredBackslash = center ("\\ " , unitSize = unitSize , fillChar = " " )
217192
218- for i in range (2 ** depth - 1 ):
219- remove = False
220- if all (
193+ for i in range (numCols ):
194+ remove = all (
221195 mat [j ][i ] in [centeredSpace , centeredSlash , centeredBackslash ]
222- for j in range (2 * depth - 1 )
223- ):
224- remove = True
196+ for j in range (numRows )
197+ )
225198 if not remove :
226199 break
227- for j in range (2 * depth - 1 ):
200+ for j in range (numRows ):
228201 mat [j ][i ] = ""
229202
230203 return mat
231204
232205
233- def nodeToString (node : BinaryNode , depth = - 1 , valueFillChar = None , gapFillChar = None , unitSize = None , removeEmpty = True ):
206+ def nodeToString (node : BinaryNode , depth = - 1 , valueFillChar = None , connectorFillChar = None , unitSize = None , removeEmpty = True ):
234207 """
235208 Converts a binary tree into a string representation for visualization.
236209
237210 Args:
238211 node: The root node of the tree to visualize
239212 depth: The depth of the tree (-1 for auto-calculation)
240- valueFillChar: Character for padding node values (uses DEFAULT_VALUE_FILL_CHAR "_" if None )
241- gapFillChar : Character for filling gaps between pairs (uses DEFAULT_GAP_FILL_CHAR "_" if None)
242- unitSize: Size for centering (uses DEFAULT_UNIT_SIZE if None)
213+ valueFillChar: Character for padding node values (e.g., "_5_" )
214+ connectorFillChar : Character for filling horizontal gaps between node pairs
215+ unitSize: Size for centering values
243216 removeEmpty: Whether to remove empty leading columns
244-
245- Returns:
246- A string representation of the tree with each row on a new line
247217 """
248- mat = nodeToMat (node , depth = depth , valueFillChar = valueFillChar , gapFillChar = gapFillChar , unitSize = unitSize , removeEmpty = removeEmpty )
218+ mat = nodeToMat (node , depth = depth , valueFillChar = valueFillChar ,
219+ connectorFillChar = connectorFillChar , unitSize = unitSize , removeEmpty = removeEmpty )
249220 return "\n " .join ("" .join (row ) for row in mat )
0 commit comments