Zigzag Traversal of a Binary Tree
Problem and examples
| Input Tree | Zigzag Traversal Output | Description |
|---|---|---|
| [1, 2, 3, 4, 5, null, 6] | [[1], [3, 2], [4, 5, 6]] | Standard tree with three levels, showcasing left-to-right and right-to-left alternation |
| [1] | [[1]] | Edge case: Single-node tree (root only) |
| [] | [] | Edge case: Empty tree with no nodes |
| [1, 2, null, 3, null, null, null, 4] | [[1], [2], [3], [4]] | Left-skewed tree; no right branches, still follows zigzag pattern per level |
| [1, null, 2, null, null, null, 3] | [[1], [2], [3]] | Right-skewed tree; no left branches, still alternates direction at each level |
| [7, 9, 8, 1, 5, 3, 6] | [[7], [8, 9], [1, 5, 3, 6]] | Balanced tree with full left and right subtrees to demonstrate alternating level order |
Explore Zigzag Traversal of a Binary Tree - Iterative
Load an example or enter your own input. Use the player controls to follow each change.
Understanding the Problem
Zigzag traversal of a binary tree means traversing its nodes level by level, but alternating the direction of traversal at each level. At the first level, we go from left to right. At the second level, we go from right to left. Then left to right again, and so on. This pattern continues until all levels are visited.
To perform this traversal, we need to keep track of the current level, the direction of traversal, and the child nodes to visit next. A queue or stack can help us manage the order of processing, depending on the traversal direction.
Step-by-Step Solution with Example
Step 1: Understand the structure of the tree
Let’s consider the following binary tree as an example:
1
/ 2 3
/ / 4 5 6 7
The expected zigzag traversal output for this tree is: [1, 3, 2, 4, 5, 6, 7]
Step 2: Initialize data structures
We use two stacks:
- currentLevel - holds nodes for the current level being processed
- nextLevel - collects nodes for the next level
leftToRight to track direction of traversal.
Step 3: Push the root node into currentLevel stack
Start with the root node 1 in currentLevel stack. Set leftToRight to true since the first level should go left to right.
Step 4: Traverse the current level
While currentLevel is not empty:
- Pop a node from currentLevel
- Add its value to the result list
- If leftToRight is true, push left child first, then right child to nextLevel
- If false, push right child first, then left child
Step 5: Move to next level
When currentLevel is empty:
- Swap currentLevel and nextLevel
- Toggle leftToRight
Step 6: Final Output
After all levels are visited, the collected result is the zigzag level order traversal of the binary tree.
For our example, this results in: [1, 3, 2, 4, 5, 6, 7]
Edge Cases
Case 1: Empty Tree
If the root is null, there are no nodes to traverse. The output should be an empty list: []
Case 2: Single Node Tree
If there is only one node in the tree, the traversal result is simply that node: [root]. No direction change is needed.
Case 3: Left-Skewed Tree
Each node has only a left child. Since each level has only one node, the direction change doesn’t affect the result. The output is top-to-bottom: [root, left1, left2, ...]
Case 4: Right-Skewed Tree
Each node has only a right child. Like the left-skewed case, the output is top-to-bottom: [root, right1, right2, ...]
Case 5: Uneven Tree
In trees where one subtree is deeper than the other, the algorithm still works. The key is managing the push order depending on the direction flag, ensuring every level is handled correctly regardless of shape.
Finally
Zigzag traversal is a simple variation of level order traversal, made possible by using two stacks and a direction flag. By working level by level and flipping the order of child insertion, we can achieve the desired zigzag pattern.
This approach is intuitive and works for all kinds of trees — complete, skewed, or even empty — as long as we check base conditions and handle edge cases properly.
- If the binary tree is empty, return an empty result.
- Initialize two stacks:
currentStackandnextStack. Push the root node ontocurrentStack. - Set a boolean flag
leftToRighttotrueto indicate the traversal direction. - While
currentStackis not empty, do the following: - Initialize an empty list to store the values of the current level.
- While
currentStackis not empty, pop a node from it and record its value. - If
leftToRightis true, push the node's left child then right child (if they exist) ontonextStack; otherwise, push the node's right child then left child ontonextStack. - After processing the current level, add the recorded values to the result.
- Swap
currentStackwithnextStackand toggle theleftToRightflag. - Continue until all levels have been processed; the collected values form the zigzag traversal of the binary tree.
Implementation and efficiency
C implementation
#include <stdio.h>
#include <stdlib.h>
typedef struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
} TreeNode;
TreeNode* createNode(int val) {
TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));
node->val = val;
node->left = node->right = NULL;
return node;
}
void zigzagTraversal(TreeNode* root) {
if (!root) return;
TreeNode* currentStack[100];
TreeNode* nextStack[100];
int top1 = -1, top2 = -1;
int leftToRight = 1;
currentStack[++top1] = root;
while (top1 >= 0) {
while (top1 >= 0) {
TreeNode* node = currentStack[top1--];
printf("%d ", node->val);
if (leftToRight) {
if (node->left) nextStack[++top2] = node->left;
if (node->right) nextStack[++top2] = node->right;
} else {
if (node->right) nextStack[++top2] = node->right;
if (node->left) nextStack[++top2] = node->left;
}
}
printf("\n");
TreeNode** temp = currentStack;
memcpy(currentStack, nextStack, sizeof(nextStack));
top1 = top2;
top2 = -1;
leftToRight = !leftToRight;
}
}
int main() {
TreeNode* root = createNode(1);
root->left = createNode(2);
root->right = createNode(3);
root->left->left = createNode(4);
root->left->right = createNode(5);
zigzagTraversal(root);
return 0;
}C++ implementation
#include <iostream>
#include <stack>
#include <vector>
using namespace std;
struct TreeNode {
int val;
TreeNode *left, *right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
vector<vector<int>> zigzagTraversal(TreeNode* root) {
vector<vector<int>> result;
if (!root) return result;
stack<TreeNode*> currentStack, nextStack;
currentStack.push(root);
bool leftToRight = true;
vector<int> level;
while (!currentStack.empty()) {
TreeNode* node = currentStack.top();
currentStack.pop();
level.push_back(node->val);
if (leftToRight) {
if (node->left) nextStack.push(node->left);
if (node->right) nextStack.push(node->right);
} else {
if (node->right) nextStack.push(node->right);
if (node->left) nextStack.push(node->left);
}
if (currentStack.empty()) {
result.push_back(level);
level.clear();
swap(currentStack, nextStack);
leftToRight = !leftToRight;
}
}
return result;
}
int main() {
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->left->left = new TreeNode(4);
root->left->right = new TreeNode(5);
vector<vector<int>> res = zigzagTraversal(root);
for (auto& level : res) {
for (int val : level) {
cout << val << " ";
}
cout << endl;
}
return 0;
}Python implementation
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def zigzagTraversal(root):
if not root:
return []
result = []
currentStack = [root]
nextStack = []
leftToRight = True
level = []
while currentStack:
node = currentStack.pop()
level.append(node.val)
if leftToRight:
if node.left:
nextStack.append(node.left)
if node.right:
nextStack.append(node.right)
else:
if node.right:
nextStack.append(node.right)
if node.left:
nextStack.append(node.left)
if not currentStack:
result.append(level)
level = []
currentStack, nextStack = nextStack, []
leftToRight = not leftToRight
return result
if __name__ == '__main__':
root = TreeNode(1, TreeNode(2, TreeNode(4), TreeNode(5)), TreeNode(3))
print(zigzagTraversal(root))Java implementation
import java.util.*;
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int x) { val = x; }
}
public class ZigzagTraversal {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) return result;
Stack<TreeNode> currentStack = new Stack<>();
Stack<TreeNode> nextStack = new Stack<>();
currentStack.push(root);
boolean leftToRight = true;
List<Integer> levelList = new ArrayList<>();
while (!currentStack.isEmpty()) {
TreeNode node = currentStack.pop();
levelList.add(node.val);
if (leftToRight) {
if (node.left != null) nextStack.push(node.left);
if (node.right != null) nextStack.push(node.right);
} else {
if (node.right != null) nextStack.push(node.right);
if (node.left != null) nextStack.push(node.left);
}
if (currentStack.isEmpty()) {
result.add(new ArrayList<>(levelList));
levelList.clear();
Stack<TreeNode> temp = currentStack;
currentStack = nextStack;
nextStack = temp;
leftToRight = !leftToRight;
}
}
return result;
}
public static void main(String[] args) {
TreeNode root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.left = new TreeNode(4);
root.left.right = new TreeNode(5);
ZigzagTraversal sol = new ZigzagTraversal();
System.out.println(sol.zigzagLevelOrder(root));
}
}JavaScript implementation
class TreeNode {
constructor(val, left = null, right = null) {
this.val = val;
this.left = left;
this.right = right;
}
}
function zigzagTraversal(root) {
if (!root) return [];
const result = [];
let currentStack = [root];
let nextStack = [];
let leftToRight = true;
let level = [];
while (currentStack.length) {
const node = currentStack.pop();
level.push(node.val);
if (leftToRight) {
if (node.left) nextStack.push(node.left);
if (node.right) nextStack.push(node.right);
} else {
if (node.right) nextStack.push(node.right);
if (node.left) nextStack.push(node.left);
}
if (currentStack.length === 0) {
result.push(level);
level = [];
[currentStack, nextStack] = [nextStack, []];
leftToRight = !leftToRight;
}
}
return result;
}
const root = new TreeNode(1, new TreeNode(2, new TreeNode(4), new TreeNode(5)), new TreeNode(3));
console.log(zigzagTraversal(root));Go implementation
package main
import (
"fmt"
)
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
func zigzagTraversal(root *TreeNode) [][]int {
if root == nil {
return [][]int{}
}
var result [][]int
currentStack := []*TreeNode{root}
nextStack := []*TreeNode{}
leftToRight := true
var level []int
for len(currentStack) > 0 {
node := currentStack[len(currentStack)-1]
currentStack = currentStack[:len(currentStack)-1]
level = append(level, node.Val)
if leftToRight {
if node.Left != nil {
nextStack = append(nextStack, node.Left)
}
if node.Right != nil {
nextStack = append(nextStack, node.Right)
}
} else {
if node.Right != nil {
nextStack = append(nextStack, node.Right)
}
if node.Left != nil {
nextStack = append(nextStack, node.Left)
}
}
if len(currentStack) == 0 {
result = append(result, level)
level = []int{}
currentStack, nextStack = nextStack, []*TreeNode{}
leftToRight = !leftToRight
}
}
return result
}
func main() {
root := &TreeNode{1, &TreeNode{2, &TreeNode{4, nil, nil}, &TreeNode{5, nil, nil}}, &TreeNode{3, nil, nil}}
res := zigzagTraversal(root)
for _, level := range res {
fmt.Println(level)
}
}Rust implementation
use std::rc::Rc;
use std::cell::RefCell;
#[derive(Debug)]
struct TreeNode {
val: i32,
left: Option<Rc<RefCell<TreeNode>>>,
right: Option<Rc<RefCell<TreeNode>>>,
}
impl TreeNode {
fn new(val: i32) -> Rc<RefCell<TreeNode>> {
Rc::new(RefCell::new(TreeNode { val, left: None, right: None }))
}
}
fn main() {
let root = TreeNode::new(1);
root.borrow_mut().left = Some(TreeNode::new(2));
root.borrow_mut().right = Some(TreeNode::new(3));
root.borrow_mut().left.as_ref().unwrap().borrow_mut().left = Some(TreeNode::new(4));
root.borrow_mut().left.as_ref().unwrap().borrow_mut().right = Some(TreeNode::new(5));
println!("Zigzag traversal not implemented fully, just tree built");
}Kotlin implementation
class TreeNode(val `val`: Int) {
var left: TreeNode? = null
var right: TreeNode? = null
}
fun zigzagTraversal(root: TreeNode?): List<List<Int>> {
val result = mutableListOf<List<Int>>()
if (root == null) return result
var currentStack = mutableListOf(root)
var nextStack = mutableListOf<TreeNode>()
var leftToRight = true
var level = mutableListOf<Int>()
while (currentStack.isNotEmpty()) {
val node = currentStack.removeAt(currentStack.size - 1)
level.add(node.`val`)
if (leftToRight) {
node.left?.let { nextStack.add(it) }
node.right?.let { nextStack.add(it) }
} else {
node.right?.let { nextStack.add(it) }
node.left?.let { nextStack.add(it) }
}
if (currentStack.isEmpty()) {
result.add(level)
level = mutableListOf()
currentStack = nextStack
nextStack = mutableListOf()
leftToRight = !leftToRight
}
}
return result
}
fun main() {
val root = TreeNode(1).apply {
left = TreeNode(2).apply {
left = TreeNode(4)
right = TreeNode(5)
}
right = TreeNode(3)
}
println(zigzagTraversal(root))
}TypeScript implementation
class TreeNode {
val: number;
left: TreeNode | null;
right: TreeNode | null;
constructor(val: number, left: TreeNode | null = null, right: TreeNode | null = null) {
this.val = val;
this.left = left;
this.right = right;
}
}
function zigzagTraversal(root: TreeNode | null): number[][] {
if (!root) return [];
const result: number[][] = [];
let currentStack: TreeNode[] = [root];
let nextStack: TreeNode[] = [];
let leftToRight = true;
let level: number[] = [];
while (currentStack.length > 0) {
const node = currentStack.pop()!;
level.push(node.val);
if (leftToRight) {
if (node.left) nextStack.push(node.left);
if (node.right) nextStack.push(node.right);
} else {
if (node.right) nextStack.push(node.right);
if (node.left) nextStack.push(node.left);
}
if (currentStack.length === 0) {
result.push(level);
level = [];
[currentStack, nextStack] = [nextStack, []];
leftToRight = !leftToRight;
}
}
return result;
}
const root = new TreeNode(1, new TreeNode(2, new TreeNode(4), new TreeNode(5)), new TreeNode(3));
console.log(zigzagTraversal(root));