Tree Width Calculation 0 based system
I was solving the classic problem of calculating the widest binary tree level - essentially finding the maximum width of in the tree. I had doubts around how left and right indices of nodes is calulated because I thought we use the standard formulas for calculating indices: left := 2i + 1 and right := 2i + 2, but it wasn't yielding the correct result.
Typically, if we want to calculate width in an array, we'd take the delta of start and end index. In a tree, it should be the same by assigning indices to each node, but here the width would be the number of nodes in that level: width = rightmost - leftmost + 1.
Okay, I get the concept, but then why aren't the typical left and right formulas working? I thought the standard formulas for left and right node indices in a tree are 2i+1 and 2i+2.
Then I understood...
The Key Insight: It's About Position, Not Traditional Indexing. The indexing formulas depend on what you're trying to achieve.
There are different systems:
Traditional Binary Heap Indexing Systems
System 1: 1 based indexing (starts from 1)
1
/ \
2 3
/ \ / \
4 5 6 7
Formulas:
Left child: 2*i
Right child: 2*i + 1
System 2: 0 based indexing (starts from 0)
0
/ \
1 2
/ \ / \
3 4 5 6
Formulas:
Left child: 2*i + 1
Right child: 2*i + 2
Reason for: Position Based Indexing for Width Calculation
A 0 based system specifically for width calculation would cause a problem. Here's why:
formulas (2i+1, 2i+2):
0
/ \
1 2 <- indices 1, 2
/ \ / \
3 4 5 6 <- indices 3, 4, 5, 6
Width calculation: rightmost - leftmost + 1 = 6 - 3 + 1 = 4
But Notice This Issue
0
/ \
1 2
/ \
3 6 <- Gap! indices 3, 6 (missing 4, 5)
Width would be: 6 - 3 + 1 = 4 but actual width is only 2 nodes!
So, if we modify the solution
By using 2i and 2i+1, the code ensures consecutive indices at each level:
0
/ \
0 1 <- 2*0=0, 2*0+1=1
/ \ / \
0 1 2 3 <- 2*0=0, 2*0+1=1, 2*1=2, 2*1+1=3
This gives relative positioning within each level, making width calculation accurate even with gaps.
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
func widestBinaryTreeLevel(root *TreeNode) int {
if root == nil {
return 0
}
maxWidth := 0
// queue stores (node, index) pairs
queue := []struct {
node *TreeNode
index int
}{{root, 0}}
for len(queue) > 0 {
levelSize := len(queue)
// Set leftmost_index to the index of the first node in this level
leftmostIndex := queue[0].index
rightmostIndex := leftmostIndex // Start at same point as leftmost
// Process all nodes at the current level
for i := 0; i < levelSize; i++ {
nodeWithIndex := queue[0]
queue = queue[1:] // popleft()
node := nodeWithIndex.node
index := nodeWithIndex.index
if node.Left != nil {
queue = append(queue, struct {
node *TreeNode
index int
}{node.Left, 2 * index}) // 2*i, not 2*i+1
}
if node.Right != nil {
queue = append(queue, struct {
node *TreeNode
index int
}{node.Right, 2*index + 1}) // 2*i+1, not 2*i+2
}
rightmostIndex = index
}
// Calculate width after processing entire level
currentWidth := rightmostIndex - leftmostIndex + 1
if currentWidth > maxWidth {
maxWidth = currentWidth
}
}
return maxWidth
}