In this blog, I will share with you what you need to know about tree data structure and how to traverse through trees.
The tree data structure consists of nodes and edges. Each node is connected through edges. Leaf nodes don’t have any children. A tree can consist of multiple subtrees with a similar structure of a parent at the top and the children directly below it. You can get a clear view of a tree data structure through the graph below:

In a non-linear data structure like a tree, we have different ways to reach a node. These include in-order traversal, pre-order traversal, and post-order traversal. The key difference among them is when to visit the root node in relation to the left node and right node.

Below is a list of practice problems from Leetcode about the tree data structure. Practicing these problems will help you better understand what the tree data structure is and how tree traversal works.
https://leetcode.com/problems/binary-tree-preorder-traversal/
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
ans = []
stack = [root]
if root is None:
return ans
while stack:
cur = stack.pop()
if cur != None:
if (cur.right != None):
stack.append(cur.right)
if (cur.left != None):
stack.append(cur.left)
stack.append(cur)
stack.append(None)
else:
ans.append(stack.pop().val)
return ans
https://leetcode.com/problems/binary-tree-postorder-traversal/
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
ans = []
stack = [root]
if root is None:
return ans
while stack:
cur = stack.pop()
if cur != None:
stack.append(cur)
stack.append(None)
if (cur.right != None):
stack.append(cur.right)
if (cur.left != None):
stack.append(cur.left)
else:
ans.append(stack.pop().val)
return ans
https://leetcode.com/problems/binary-tree-inorder-traversal/
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
ans = []
stack = [root]
if root is None:
return ans
while stack:
cur = stack.pop()
if cur != None:
if cur.right != None:
stack.append(cur.right)
stack.append(cur)
stack.append(None)
if cur.left != None:
stack.append(cur.left)
else:
ans.append(stack.pop().val)
return ans
https://leetcode.com/problems/binary-tree-level-order-traversal/
class Solution:
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
ans = []
if root is None:
return ans
q = deque([root])
while q:
level = []
for _ in range(len(q)):
node = q.popleft()
level.append(node.val)
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
ans.append(level)
return ans
https://leetcode.com/problems/binary-tree-level-order-traversal-ii/
class Solution:
def levelOrderBottom(self, root: Optional[TreeNode]) -> List[List[int]]:
ans = []
if root is None:
return ans
q = deque([root])
while q:
level = []
for _ in range(len(q)):
node = q.popleft()
level.append(node.val)
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
ans.append(level)
return ans[::-1]
https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/
class Solution:
def zigzagLevelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
ans = []
if root is None:
return ans
q = deque([root])
left_to_right = True
while q:
level = []
for _ in range(len(q)):
node = q.popleft()
level.append(node.val)
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
if left_to_right:
ans.append(level)
else:
ans.append(level[::-1])
left_to_right = not left_to_right
return ans
https://leetcode.com/problems/n-ary-tree-level-order-traversal/
class Solution:
def levelOrder(self, root: 'Node') -> List[List[int]]:
ans = []
if root is None:
return ans
q = deque([root])
while q:
level = []
for _ in range(len(q)):
cur = q.popleft()
level.append(cur.val)
for child in cur.children:
q.append(child)
ans.append(level)
return ans
https://leetcode.com/problems/check-completeness-of-a-binary-tree/
class Solution:
def isCompleteTree(self, root: Optional[TreeNode]) -> bool:
q = deque([root])
zero = False
while q:
cur = q.popleft()
if cur is None:
zero = True
if zero and cur != None:
return False
if cur != None:
q.append(cur.left)
q.append(cur.right)
return True
https://leetcode.com/problems/find-bottom-left-tree-value/
class Solution:
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
q = deque([root])
while q:
cur = q.popleft()
if cur.right:
q.append(cur.right)
if cur.left:
q.append(cur.left)
return cur.val
https://leetcode.com/problems/even-odd-tree/
class Solution:
def isEvenOddTree(self, root: Optional[TreeNode]) -> bool:
q = deque([root])
level = 0
while q:
arr = []
for i in range(len(q)):
cur = q.popleft()
arr.append(cur.val)
if level % 2 == 0:
if arr[i] % 2 == 0:
return False
if i > 0 and arr[i] <= arr[i - 1]:
return False
else:
if arr[i] % 2 != 0:
return False
if i > 0 and arr[i] >= arr[i - 1]:
return False
if cur.left:
q.append(cur.left)
if cur.right:
q.append(cur.right)
level += 1
return True
https://leetcode.com/problems/n-ary-tree-preorder-traversal/
class Solution:
def preorder(self, root: 'Node') -> List[int]:
ans = []
if root is None:
return ans
stack = [root]
while stack:
cur = stack.pop()
if cur != None:
for i in range(len(cur.children) - 1, -1, -1):
stack.append(cur.children[i])
stack.append(cur)
stack.append(None)
else:
ans.append(stack.pop().val)
return ans
https://leetcode.com/problems/n-ary-tree-postorder-traversal/
class Solution:
def postorder(self, root: 'Node') -> List[int]:
ans = []
if root is None:
return ans
stack = [root]
while stack:
cur = stack.pop()
if cur != None:
stack.append(cur)
stack.append(None)
for i in range(len(cur.children) - 1, -1, -1):
stack.append(cur.children[i])
else:
ans.append(stack.pop().val)
return ans
https://leetcode.com/problems/binary-tree-right-side-view/
class Solution:
def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
ans = []
if root is None:
return ans
q = deque([root])
while q:
k = len(q)
for i in range(k):
cur = q.popleft()
if i == k - 1:
ans.append(cur.val)
if cur.left:
q.append(cur.left)
if cur.right:
q.append(cur.right)
return ans
https://leetcode.com/problems/maximum-depth-of-binary-tree/
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if root is None:
return 0
return max(self.maxDepth(root.left), self.maxDepth(root.right)) + 1
https://leetcode.com/problems/maximum-depth-of-n-ary-tree/
class Solution:
def maxDepth(self, root: 'Node') -> int:
if root is None:
return 0
ans = 1
for child in root.children:
ans = max(self.maxDepth(child) + 1, ans)
return ans
https://leetcode.com/problems/subtree-of-another-tree/
class Solution:
def isSubtree(self, root: Optional[TreeNode], subRoot: Optional[TreeNode]) -> bool:
if self.sameTree(root, subRoot):
return True
return (root.left != None and self.isSubtree(root.left, subRoot)) or (root.right != None and self.isSubtree(root.right, subRoot))
def sameTree(self, a, b):
if a == None and b == None:
return True
return a != None and b != None and a.val == b.val and self.sameTree(a.left, b.left) and self.sameTree(a.right, b.right)
https://leetcode.com/problems/symmetric-tree/
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
if root is None:
return True
def helper(a, b):
if a is None and b is None:
return True
if a is None or b is None:
return False
return a.val == b.val and helper(a.left, b.right) and helper(a.right, b.left)
return helper(root.left, root.right)
https://leetcode.com/problems/invert-binary-tree/
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if root is None:
return None
temp = self.invertTree(root.right)
root.right = self.invertTree(root.left)
root.left = temp
return root
https://leetcode.com/problems/merge-two-binary-trees/
class Solution:
def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
if root1 is None and root2 is None:
return None
if root1 is None and root2 is not None:
return root2
if root1 is not None and root2 is None:
return root1
root1.val += root2.val
root1.left = self.mergeTrees(root1.left, root2.left)
root1.right = self.mergeTrees(root1.right, root2.right)
return root1
https://leetcode.com/problems/balanced-binary-tree/
class Solution:
def isBalanced(self, root: Optional[TreeNode]) -> bool:
if root is None:
return True
if abs(self.height(root.left) - self.height(root.right)) > 1:
return False
return self.isBalanced(root.left) and self.isBalanced(root.right)
def height(self, root):
if root is None:
return 0
return max(self.height(root.left), self.height(root.right)) + 1
https://leetcode.com/problems/flatten-binary-tree-to-linked-list/
class Solution:
def __init__(self):
self.ans = None
def flatten(self, root: Optional[TreeNode]) -> None:
if root is None:
return
self.flatten(root.right)
self.flatten(root.left)
root.right = self.ans
root.left = None
self.ans = root
https://leetcode.com/problems/sum-of-left-leaves/
class Solution:
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
self.ans = 0
def helper(node):
if node is None:
return 0
if node.left != None and node.left.left == None and node.left.right == None:
self.ans += node.left.val
helper(node.left)
helper(node.right)
helper(root)
return self.ans
https://leetcode.com/problems/binary-tree-longest-consecutive-sequence/
class Solution:
def longestConsecutive(self, root: Optional[TreeNode]) -> int:
self.max = 1
def helper(node, cnt):
self.max = max(self.max, cnt)
if node.left:
if node.left.val == node.val + 1:
helper(node.left, cnt + 1)
else:
helper(node.left, 1)
if node.right:
if node.right.val == node.val + 1:
helper(node.right, cnt + 1)
else:
helper(node.right, 1)
helper(root, 1)
return self.max
https://leetcode.com/problems/sum-root-to-leaf-numbers/
class Solution:
def sumNumbers(self, root: Optional[TreeNode]) -> int:
def helper(node, num):
if node is None:
return 0
num = num * 10 + node.val
if node.left == None and node.right == None:
return num
return helper(node.left, num) + helper(node.right, num)
return helper(root, 0)
https://leetcode.com/problems/populating-next-right-pointers-in-each-node/
class Solution:
def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
if root == None:
return
q = deque([root])
while q:
k = len(q)
level = []
for _ in range(k):
node = q.popleft()
level.append(node)
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
for i in range(len(level) - 1):
level[i].next = level[i + 1]
return root
https://leetcode.com/problems/count-complete-tree-nodes/
class Solution:
def countNodes(self, root: Optional[TreeNode]) -> int:
if root == None:
return 0
def dep(node):
if node == None:
return 0
return 1 + dep(node.left)
l, r = dep(root.left), dep(root.right)
if l == r:
return 2 ** l + self.countNodes(root.right)
else:
return 2 ** r + self.countNodes(root.left)
https://leetcode.com/problems/increasing-order-search-tree/
class Solution:
def increasingBST(self, root: TreeNode) -> TreeNode:
dummy = TreeNode(-1)
self.cur = dummy
def dfs(node):
if node == None:
return
dfs(node.left)
self.cur.right = node
node.left = None
self.cur = self.cur.right
dfs(node.right)
dfs(root)
return dummy.right