C++ · Course navigation

C++ binary search tree traversals

Insert values into a BST and visit them depth-first and level by level.

On this page
Before you start

C++ recursion, smart pointers, and queues.

  • Insert values into a BST and visit them depth-first and level by level.
  • Predict the sample output and explain the state changes.
  • Complete the practice task and check the boundary cases.

The concept

A binary search tree keeps smaller values in the left subtree and larger values in the right. A depth-first in-order traversal visits left, node, right, which yields the values in sorted order. A level-order traversal, also called breadth-first, visits all nodes of one depth before the next and uses a queue: pop a node, process it, and push its children.

These two orders answer different questions. In-order gives sorted output. Level order shows the shape of the tree and finds the shallowest node satisfying a condition first. Both visit every node once, so they take O(n) time. The recursion depth of the depth-first version equals the height of the tree.

Code example

C++
#include <iostream>
#include <memory>
#include <queue>

struct Node {
  int value;
  std::unique_ptr<Node> left;
  std::unique_ptr<Node> right;
  explicit Node(int v) : value(v) {}
};

void insert(std::unique_ptr<Node>& root, int value) {
  if (!root) {
    root = std::make_unique<Node>(value);
  } else if (value < root->value) {
    insert(root->left, value);
  } else if (value > root->value) {
    insert(root->right, value);
  }
}

void in_order(const Node* node) {
  if (node == nullptr) {
    return;
  }
  in_order(node->left.get());
  std::cout << " " << node->value;
  in_order(node->right.get());
}

void level_order(const Node* root) {
  std::queue<const Node*> pending;
  pending.push(root);
  while (!pending.empty()) {
    const Node* node = pending.front();
    pending.pop();
    std::cout << " " << node->value;
    if (node->left) pending.push(node->left.get());
    if (node->right) pending.push(node->right.get());
  }
}

int main() {
  std::unique_ptr<Node> root;
  for (int v : {50, 30, 70, 20, 40, 60, 80}) {
    insert(root, v);
  }
  std::cout << "in order:";
  in_order(root.get());
  std::cout << "\nlevel order:";
  level_order(root.get());
  std::cout << "\n";
}
Output
in order: 20 30 40 50 60 70 80
level order: 50 30 70 20 40 60 80

Follow the code

Open the walkthrough to inspect the example one step at a time.

Show guided walkthrough
Guided walkthroughReady
1#include <iostream>
2#include <memory>
3#include <queue>
4
5struct Node {
6 int value;
7 std::unique_ptr<Node> left;
8 std::unique_ptr<Node> right;
9 explicit Node(int v) : value(v) {}
10};
11
12void insert(std::unique_ptr<Node>& root, int value) {
13 if (!root) {
14 root = std::make_unique<Node>(value);
15 } else if (value < root->value) {
16 insert(root->left, value);
17 } else if (value > root->value) {
18 insert(root->right, value);
19 }
20}
21
22void in_order(const Node* node) {
23 if (node == nullptr) {
24 return;
25 }
26 in_order(node->left.get());
27 std::cout << " " << node->value;
28 in_order(node->right.get());
29}
30
31void level_order(const Node* root) {
32 std::queue<const Node*> pending;
33 pending.push(root);
34 while (!pending.empty()) {
35 const Node* node = pending.front();
36 pending.pop();
37 std::cout << " " << node->value;
38 if (node->left) pending.push(node->left.get());
39 if (node->right) pending.push(node->right.get());
40 }
41}
42
43int main() {
44 std::unique_ptr<Node> root;
45 for (int v : {50, 30, 70, 20, 40, 60, 80}) {
46 insert(root, v);
47 }
48 std::cout << "in order:";
49 in_order(root.get());
50 std::cout << "\nlevel order:";
51 level_order(root.get());
52 std::cout << "\n";
53}

Follow the example

Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.

View the complete dry-run table
Prepared trace of the published program. Some rows group repeated iterations.
Step / lineWhat happensState after stepOutput so far
Taking the owning pointer by reference lets insert fill an empty spot in place.—
—
An empty position: create the node here.—
—
Visit the whole left subtree first.—
—
Depth-first, left–node–right.—
—
Start the breadth-first search with the root.—
—
Children join the back of the queue, so the next level is visited after this one.—
—
Print both orders: in-order is sorted; level order shows 50 at the top, then its children, then theirs.—
in order: 20 30 40 50 60 70 80
level order: 50 30 70 20 40 60 80

Behind the scenes

How C++ processes this code

The C++ compiler produces a native executable. Execution enters main, where objects and function calls perform the work.

Cost and common mistakes

Both traversals are O(n). Level order needs O(w) extra space for the widest level w.

  • level_order assumes the root is not null. Add a check for an empty tree.
  • Deep recursion on a degenerate (chain-shaped) tree can overflow the stack.
  • Pushing raw pointers into the queue is safe here because the tree outlives the traversal and the queue does not own the nodes.

Try it yourself

How would you print the tree height with level order?

Reveal answer and reasoning

Process the queue one level at a time (using the queue size at the start of each level) and count the number of levels.

Further reading