0
0
DSA Goprogramming

Top View of Binary Tree in DSA Go

Choose your learning style9 modes available
Mental Model
We want to see the nodes visible when looking at the tree from above, ignoring nodes hidden behind others.
Analogy: Imagine standing on a balcony looking down at a garden with trees; you only see the tops of some branches, not the ones hidden behind.
       1
      / \
     2   3
      \   \
       4   5

Top view shows nodes: 2 -> 1 -> 3 -> 5
Dry Run Walkthrough
Input: Binary tree: 1 is root, 2 left child, 3 right child, 4 right child of 2, 5 right child of 3
Goal: Find nodes visible from top view: nodes that appear first at each horizontal distance from root
Step 1: Start at root node 1 with horizontal distance (hd) 0
Queue: [(1, hd=0)]
Top view map: {}
Why: We begin BFS from root to explore nodes level by level
Step 2: Visit node 1 at hd=0, add to top view map since hd=0 not seen before
Top view map: {0:1}
Queue: [(2, hd=-1), (3, hd=1)]
Why: First node at hd=0 is 1, add children with updated hd
Step 3: Visit node 2 at hd=-1, add to top view map since hd=-1 not seen before
Top view map: {-1:2, 0:1}
Queue: [(3, hd=1), (4, hd=0)]
Why: First node at hd=-1 is 2, add its right child with hd=0
Step 4: Visit node 3 at hd=1, add to top view map since hd=1 not seen before
Top view map: {-1:2, 0:1, 1:3}
Queue: [(4, hd=0), (5, hd=2)]
Why: First node at hd=1 is 3, add its right child with hd=2
Step 5: Visit node 4 at hd=0, skip adding to map since hd=0 already has node 1
Top view map unchanged: {-1:2, 0:1, 1:3}
Queue: [(5, hd=2)]
Why: Node 4 is hidden behind node 1 from top view
Step 6: Visit node 5 at hd=2, add to top view map since hd=2 not seen before
Top view map: {-1:2, 0:1, 1:3, 2:5}
Queue: []
Why: First node at hd=2 is 5
Result:
Top view nodes in order of hd: 2 -> 1 -> 3 -> 5
Annotated Code
DSA Go
package main

import (
	"container/list"
	"fmt"
	"sort"
)

type Node struct {
	Val   int
	Left  *Node
	Right *Node
}

func topView(root *Node) []int {
	if root == nil {
		return []int{}
	}

	// Map to store first node at each horizontal distance
	hdNodeMap := make(map[int]int)

	// Queue for BFS: stores pairs of node and its horizontal distance
	queue := list.New()
	queue.PushBack(struct {
		node *Node
		hd   int
	}{root, 0})

	for queue.Len() > 0 {
		front := queue.Front()
		queue.Remove(front)
		curr := front.Value.(struct {
			node *Node
			hd   int
		})

		// If hd not seen before, add node value
		if _, exists := hdNodeMap[curr.hd]; !exists {
			hdNodeMap[curr.hd] = curr.node.Val
		}

		// Add left child with hd-1
		if curr.node.Left != nil {
			queue.PushBack(struct {
				node *Node
				hd   int
			}{curr.node.Left, curr.hd - 1})
		}

		// Add right child with hd+1
		if curr.node.Right != nil {
			queue.PushBack(struct {
				node *Node
				hd   int
			}{curr.node.Right, curr.hd + 1})
		}
	}

	// Extract keys and sort to print top view from left to right
	keys := []int{}
	for k := range hdNodeMap {
		keys = append(keys, k)
	}
	sort.Ints(keys)

	result := []int{}
	for _, k := range keys {
		result = append(result, hdNodeMap[k])
	}
	return result
}

func main() {
	// Construct tree:
	//       1
	//      / \
	//     2   3
	//      \   \
	//       4   5

	root := &Node{Val: 1}
	root.Left = &Node{Val: 2}
	root.Right = &Node{Val: 3}
	root.Left.Right = &Node{Val: 4}
	root.Right.Right = &Node{Val: 5}

	tv := topView(root)
	for i, v := range tv {
		if i > 0 {
			fmt.Print(" -> ")
		}
		fmt.Print(v)
	}
	fmt.Println()
}
queue.PushBack(struct { node *Node; hd int }{root, 0})
Initialize BFS queue with root at horizontal distance 0
front := queue.Front() queue.Remove(front) curr := front.Value.(struct { node *Node; hd int })
Dequeue current node and its horizontal distance for processing
if _, exists := hdNodeMap[curr.hd]; !exists { hdNodeMap[curr.hd] = curr.node.Val }
Add node value to map if this horizontal distance is seen first time
if curr.node.Left != nil { queue.PushBack(struct { node *Node; hd int }{curr.node.Left, curr.hd - 1}) }
Add left child with horizontal distance decreased by 1
if curr.node.Right != nil { queue.PushBack(struct { node *Node; hd int }{curr.node.Right, curr.hd + 1}) }
Add right child with horizontal distance increased by 1
sort.Ints(keys)
Sort horizontal distances to print top view from left to right
OutputSuccess
2 -> 1 -> 3 -> 5
Complexity Analysis
Time: O(n) because we visit each node once in BFS
Space: O(n) for queue and map storing nodes and horizontal distances
vs Alternative: Compared to DFS, BFS ensures first node at each horizontal distance is found level-wise, avoiding overwriting nodes visible from top
Edge Cases
Empty tree
Returns empty list since no nodes to view
DSA Go
if root == nil { return []int{} }
Tree with single node
Returns list with only root node value
DSA Go
if root == nil { return []int{} }
Multiple nodes at same horizontal distance but different levels
Only the topmost (first encountered in BFS) node is included
DSA Go
if _, exists := hdNodeMap[curr.hd]; !exists { hdNodeMap[curr.hd] = curr.node.Val }
When to Use This Pattern
When asked to find nodes visible from top or bottom in a binary tree, use BFS with horizontal distance tracking to capture first or last nodes at each horizontal distance.
Common Mistakes
Mistake: Using DFS which may overwrite nodes at same horizontal distance and miss top view nodes
Fix: Use BFS to ensure first node at each horizontal distance is recorded
Mistake: Not tracking horizontal distance, leading to incorrect nodes in top view
Fix: Track horizontal distance for each node relative to root
Summary
Finds nodes visible when looking at a binary tree from above by tracking horizontal distances.
Use when you need to print or find the top view of a binary tree.
The key is to record the first node encountered at each horizontal distance during a level order traversal.