Binary Tree: Traversal Methods and Level Order Problems
Binary Tree Terminology
- Root Node: A node with no parent.
- Leaf Node: A node with no children.
- Edge: The line segment connecting two nodes.
- Level: Incrementing from top to bottom, with the topmost level being 1.
- Degree of a Node: The number of child nodes it has.
- Height of a Binary Tree: The length (number of edges) from the root node to the farthest leaf node.
- Depth of a Node: The length (number of edges) from the node to the root.
- Height of a Node: The length (number of edges) from the node to the farhtest leaf node.
Preorder, Inorder, and Postorder Traversals (Recursive)
To determine the order: look at when the root node is visited.
- Preorder: Root, Left, Right.
- Inorder: Left, Root, Right (starts from the leftmost node).
- Postorder: Left, Right, Root.
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
// Preorder traversal
void traverse(TreeNode* node, vector<int>& result) {
if (node == nullptr) return;
result.push_back(node->val);
traverse(node->left, result);
traverse(node->right, result);
}
// Inorder traversal
void traverseIn(TreeNode* node, vector<int>& result) {
if (node == nullptr) return;
traverseIn(node->left, result);
result.push_back(node->val);
traverseIn(node->right, result);
}
// Postorder traversal
void traversePost(TreeNode* node, vector<int>& result) {
if (node == nullptr) return;
traversePost(node->left, result);
traversePost(node->right, result);
result.push_back(node->val);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
traverse(root, result);
return result;
}
};
Level Order Traversal
Idea: Traverse the tree from top to bottom and left to right.
LeetCode 102: Binary Tree Level Order Traversal
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*> q;
q.push(root);
vector<vector<int>> result;
if (root == nullptr) return result;
while (!q.empty()) {
int levelSize = q.size();
vector<int> currentLevel;
for (int i = 0; i < levelSize; ++i) {
TreeNode* node = q.front();
q.pop();
currentLevel.push_back(node->val);
if (node->left != nullptr) {
q.push(node->left);
}
if (node->right != nullptr) {
q.push(node->right);
}
}
result.push_back(currentLevel);
}
return result;
}
};
LeetCode 107: Binary Tree Level Order Traversal II
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
queue<TreeNode*> q;
q.push(root);
vector<vector<int>> result;
if (root == nullptr) return result;
while (!q.empty()) {
int levelSize = q.size();
vector<int> currentLevel;
for (int i = 0; i < levelSize; ++i) {
TreeNode* node = q.front();
q.pop();
currentLevel.push_back(node->val);
if (node->left != nullptr) {
q.push(node->left);
}
if (node->right != nullptr) {
q.push(node->right);
}
}
// The only difference from top-down: insert at the beginning
result.insert(result.begin(), currentLevel);
}
return result;
}
};
LeetCode 199: Binary Tree Right Side View
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
queue<TreeNode*> q;
q.push(root);
vector<int> result;
if (root == nullptr) return result;
while (!q.empty()) {
int levelSize = q.size();
vector<int> currentLevel;
for (int i = 0; i < levelSize; ++i) {
TreeNode* node = q.front();
q.pop();
currentLevel.push_back(node->val);
if (node->left != nullptr) {
q.push(node->left);
}
if (node->right != nullptr) {
q.push(node->right);
}
}
// Only store the rightmost value of each level
result.push_back(currentLevel.back());
}
return result;
}
};
LeetCode 637: Average of Levels in Binary Tree
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
queue<TreeNode*> q;
q.push(root);
vector<double> result;
if (root == nullptr) return result;
while (!q.empty()) {
int levelSize = q.size();
double sum = 0;
for (int i = 0; i < levelSize; ++i) {
TreeNode* node = q.front();
q.pop();
sum += node->val;
if (node->left != nullptr) {
q.push(node->left);
}
if (node->right != nullptr) {
q.push(node->right);
}
}
result.push_back(sum / levelSize);
}
return result;
}
};
LeetCode 102: N-ary Tree Level Order Traversal
Note: The N-ary tree node uses a vector of children pointers instead of left and right.
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> children;
Node() {}
Node(int _val) {
val = _val;
}
Node(int _val, vector<Node*> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public:
vector<vector<int>> levelOrder(Node* root) {
queue<Node*> q;
q.push(root);
vector<vector<int>> result;
if (root == nullptr) return result;
while (!q.empty()) {
int levelSize = q.size();
vector<int> currentLevel;
for (int i = 0; i < levelSize; ++i) {
Node* node = q.front();
q.pop();
currentLevel.push_back(node->val);
for (auto child : node->children) {
if (child != nullptr) {
q.push(child);
}
}
}
result.push_back(currentLevel);
}
return result;
}
};
LeetCode 515: Find Largest Value in Each Tree Row
class Solution {
public:
vector<int> largestValues(TreeNode* root) {
queue<TreeNode*> q;
q.push(root);
vector<int> result;
if (root == nullptr) return result;
while (!q.empty()) {
int levelSize = q.size();
int maxVal = INT_MIN;
for (int i = 0; i < levelSize; ++i) {
TreeNode* node = q.front();
q.pop();
maxVal = max(maxVal, node->val);
if (node->left != nullptr) {
q.push(node->left);
}
if (node->right != nullptr) {
q.push(node->right);
}
}
result.push_back(maxVal);
}
return result;
}
};