Topics › Binary Search Trees › Practice Problems
Insert a given node in BST
LeetCode ↗ Java source ↗ Edit this article ↗
Jump to code:
Problem
You are given the root of a binary search tree and a value val that is not already in the tree. Insert val so that the tree is still a BST, and return the root of the resulting tree. Several valid trees may exist; the standard answer, and the one produced here, adds val as a new leaf and leaves every existing link in place.
Constraints: up to 10^4 nodes; all keys and val are distinct and fit in an int.
Example 1
4 4
/ \ / \
2 7 val = 5 2 7
/ \ / \ /
1 3 1 3 5
5 > 4, so it belongs right of the root; 5 < 7, so it belongs left of 7, which is an empty slot. Output in level order: [4, 2, 7, 1, 3, 5].
Example 2
root = [40, 20, 60, 10, 30, 50, 70], val = 25
answer = [40, 20, 60, 10, 30, 50, 70, null, null, 25]
25 < 40 goes left, 25 > 20 goes right, 25 < 30 goes left, which is empty: 25 becomes the left child of 30.
Why the new key belongs at the end of its search path
Search for val as if it were in the tree. Since it is not, the search ends by stepping into an empty child slot. Put the new node exactly there.
This keeps the BST property for every node. Take any ancestor a on the path. We went left at a exactly when val < a.val, so the new node lands in the left subtree of a only when it is smaller, and in the right subtree only when it is larger. Every constraint along the path is satisfied. Nodes that are not on the path do not get a new descendant, so their constraints are unaffected. Nothing else in the tree moves.
It is also the only place a leaf can go: any other empty slot is in a subtree that some comparison on the path ruled out.
There is no meaningful brute force here. One could collect all keys, add val and rebuild a tree from scratch in O(n), but that discards the structure for no gain. The two approaches below are the same walk written two ways.
Approach 1: Recursive descent
Intuition. Let the function mean “insert val into this subtree and return the subtree’s root”. For an empty subtree, the answer is a brand-new node. For a non-empty one, insert into the correct side and reattach the result as that child. On every level except the bottom, the reattachment writes back the same child it already had; at the bottom it links in the new node. The same rule also handles an empty tree: the new node becomes the root and is returned.
Algorithm.
- If
rootisnull, returnnew TreeNode(val). - If
val < root.val, setroot.left = recursive(root.left, val). - Otherwise set
root.right = recursive(root.right, val). - Return
root.
static TreeNode recursive(TreeNode root, int val) {
if (root == null) return new TreeNode(val); // fell off the tree: this empty spot is where val belongs
if (val < root.val) root.left = recursive(root.left, val);
else root.right = recursive(root.right, val);
return root;
}
Complexity. Time O(h): one call per level of the search path. Space O(h) for the recursion stack, where h is the height.
Approach 2: Optimal, iterative descent
Intuition. The loop has to stop one step earlier than a plain search. A search moves cur until it becomes null, but by then the parent is lost, and the parent is the node whose child link we must set. So at each node we look at the child we are about to move to: if it is empty, link the new node there and stop; otherwise move to it.
Algorithm.
- Create
node = new TreeNode(val). Ifrootisnull, returnnode. - Set
cur = rootand loop:- if
val < cur.val: ifcur.leftis empty, setcur.left = nodeand stop; otherwise move left; - else: if
cur.rightis empty, setcur.right = nodeand stop; otherwise move right.
- if
- Return
root, which has not changed.
static TreeNode optimal(TreeNode root, int val) {
TreeNode node = new TreeNode(val);
if (root == null) return node;
TreeNode cur = root;
while (true) {
if (val < cur.val) {
if (cur.left == null) { cur.left = node; break; }
cur = cur.left;
} else {
if (cur.right == null) { cur.right = node; break; }
cur = cur.right;
}
}
return root;
}
Dry run on Example 2 (val = 25):
| cur | comparison | child on that side | action |
|---|---|---|---|
| 40 | 25 < 40 | left = 20 | move to 20 |
| 20 | 25 > 20 | right = 30 | move to 30 |
| 30 | 25 < 30 | left = null | link 25 as left child, stop |
Complexity. Time O(h), Space O(1). The while (true) loop always terminates: each iteration moves one level down, and the tree has finite height, so an empty slot is reached after at most h steps.
Repeated insertion and tree shape
Inserting keys one by one is the standard way to build a BST, and the final shape depends entirely on the order. The Java file inserts a fixed permutation of 1..100 with both methods, checks that they produce the identical tree, and checks that its inorder traversal is exactly 1, 2, ..., 100. If the keys had arrived in sorted order instead, every insertion would go right at every node and the result would be a chain of height 100, where every later operation costs O(n). Self-balancing trees (AVL, red-black) add rotations after each insertion to prevent that; plain leaf insertion does not.
Edge cases and pitfalls
- Empty tree. The new node becomes the root. Callers must use the returned value:
root = insert(root, val). Callinginsert(root, val)and ignoring the result loses the new node whenrootwasnull. - New minimum or maximum. The walk follows the left or right edge to the end; for example inserting
0into Example 1 makes it the left child of1. - The parent can be an internal node. The new node is always a leaf, but its parent need not have been one. Inserting
8into the two-node tree with root5and left child3fills the empty right slot of the root. - Duplicates. The problem guarantees
valis absent. If duplicates were possible, these methods would send an equal key right; whatever convention you choose must match search and delete. - Extreme values. Only comparisons are used, so
Integer.MIN_VALUEandInteger.MAX_VALUEinsert like any other key. - Recursion depth. On a long chain the recursive version goes
hframes deep; the loop does not.
Related problems
- Introduction to BST shows how insertion order decides whether the tree is balanced or a chain.
- Search in a Binary Search Tree is the walk this insertion is built on.
- Delete a node in BST is the reverse operation and the harder one.
- Construct a BST from a preorder traversal can be solved by repeated insertion, and faster with bounds.
- Find Min/Max in BST walks the edges that a new minimum or maximum is appended to.