Binary Trees · 18 of 35
Convert Binary tree into Doubly Linked List
Turn a tree into a two-way chain of the same nodes, in left to right order, by reusing the left and right arrows of each node as back and next.
- Simple way
- time O(n)
room O(n) - Clever way
- time O(n)
room O(h)
The problem, simply
You get a binary tree. Rearrange its arrows so the nodes form a doubly linked list: a chain where each box points to the next box and also back to the box before it.
- The order of the chain is the left to right reading order of the tree (inorder).
- Use the same nodes. A node's
leftarrow becomes "back" and itsrightarrow becomes "next". - Give back the first box of the chain, the head.
A story to remember it
Picture it
The tree, and the chain we want. Reading the tree from left to right gives 25, 12, 30, 10, 36, 15.
Examples
A small tree
- In
[10, 12, 15, 25, 30, 36]- Out
25 <-> 12 <-> 30 <-> 10 <-> 36 <-> 15
Left to right reading order.
A search tree comes out sorted
- In
[4, 2, 5, 1, 3]- Out
1 <-> 2 <-> 3 <-> 4 <-> 5
In a binary search tree the left to right order is the sorted order.
A left chain
- In
[1, 2, null, 3]- Out
3 <-> 2 <-> 1
The deepest node is the leftmost, so it becomes the head.
One node
- In
[7]- Out
7
A chain of one box. Both its arrows are null.
Empty tree
- In
[]- Out
null
Nothing to link.
Way 1: the simple way
Read the tree left to right and put every node in a list. Then walk the list and set the arrows from neighbor to neighbor.
- Do an inorder walk and add each node to a list.
- For each position
i, setleftto the node ati - 1(or null) andrightto the node ati + 1(or null). - Return the first node.
import java.util.*;
class Solution {
public TreeNode toDLL(TreeNode root) {
if (root == null) return null;
List<TreeNode> order = new ArrayList<>();
inorder(root, order);
for (int i = 0; i < order.size(); i++) {
TreeNode cur = order.get(i);
cur.left = (i > 0) ? order.get(i - 1) : null; // back
cur.right = (i + 1 < order.size()) ? order.get(i + 1) : null; // next
}
return order.get(0);
}
private void inorder(TreeNode n, List<TreeNode> order) {
if (n == null) return;
inorder(n.left, order);
order.add(n);
inorder(n.right, order);
}
}How long it takes: one walk and one pass over the list, O(n). Extra room: the list holds every node, O(n).
Way 2: the clever way
Skip the list. Link the nodes during the walk. Keep a finger prev on the last node added to the chain.
- Walk the tree in inorder.
- When you reach a node: if
previs null, this node is the head. Otherwise linkprev.right = nodeandnode.left = prev. - Move
prevto this node and continue with the right side.
It is safe to change the arrows while walking. When we reach a node, its left side is already finished, so we can reuse node.left. And prev.right either was empty or pointed into the part we are walking now, which the walk already holds on to.
Link each node to the one before it
01 / 08
Read the tree left to right (inorder). Keep a finger prev on the last box we added to the chain. At the start the chain is empty and prev is null.
- prev
- null
- head
- null
- looking now
- done
- answer
- just added
- ignored
class Solution {
private TreeNode prev, head;
public TreeNode toDLL(TreeNode root) {
prev = null;
head = null;
link(root);
return head;
}
private void link(TreeNode node) {
if (node == null) return;
link(node.left); // everything on the left joins first
if (prev == null) head = node; // the leftmost node starts the chain
else {
prev.right = node; // next
node.left = prev; // back
}
prev = node;
link(node.right);
}
}How long it takes: each node is visited once, O(n). Extra room: only the waiting helpers, as many as the tree is tall, O(h). That is O(log n) for a bushy tree and O(n) for a stick shaped one.
Watch out for
- Not resetting
prevandheadbetween calls when they are fields. - Linking only one way. A doubly linked list needs both
prev.right = nodeandnode.left = prev. - The ends. The head's
leftand the tail'srightshould be null. Here they already are: the leftmost node has no left child, and the rightmost node has no right child.
What interviewers ask next
- Make it circular? After the walk, link the tail (
prev) and the head:prev.right = headandhead.left = prev. That is LeetCode 426. - True
O(1)extra room? Use a Morris walk, which borrows empty right arrows to find the way back instead of a call stack. It visits each node a few times but uses no stack. - Flatten into a list in preorder using only
rightarrows? That is LeetCode 114. Walk right side first and keep aprev, or move each left subtree in between. - Merge two search trees? Turn both into sorted chains like this, merge the chains, then build a balanced tree from the merged chain.
Remember this
Grown-up words: the line of kids is a doubly linked list, left to right reading is inorder traversal, the finger is the prev pointer, and the walk that borrows arrows is Morris traversal.