Given a Binary Tree (BT), convert it to a Doubly Linked List(DLL) (In-Place).
Detailed
Given a binary tree, convert it into a doubly linked list (DLL) in-place. The DLL should represent the in-order traversal of the binary tree, where the left child becomes the previous link, and the right child becomes the next link of the DLL.
Input:
10
/\ 12 15
/\ 25 30
Output:
25 <-> 12 <-> 30 <-> 10 <-> 15
Explanation: The in-order traversal of the binary tree gives [25, 12, 30, 10, 15]. These nodes must be linked as a doubly linked list.
As we discussed earlier we can reuse left and right pointers to connect link list nodes so, we can create DLL by doing inorder traversal and connecting nodes by their left and right nodes along the traversal path.
First question you should be asking is which node should be the head of doubly linked list? If left most node in binary tree is to be head, you need to traverse tree in inorder. However if root node has to be head node, then you should do preorder traversal.
To convert binary tree to linked list, at each node, previous pointer will point to the inorder predecessor of the node where as next pointer points to inorder successor of node.
The in-order traversal of a binary tree is a natural choice for converting it into a doubly linked list because the left-to-right order of nodes perfectly aligns with the sequential arrangement in a DLL.
The goal is to:
Traverse the binary tree in in-order fashion.
Link the nodes being visited such that the left pointer represents the previous node, and the right pointer represents the next node in the resultant doubly linked list.
classSolution {
// Pointer to track previous node as we traverseprivate TreeNode prev =null;
// Method to convert Binary Tree to Doubly Linked Listpublic TreeNode BTtoDLL(TreeNode root) {
if (root ==null) returnnull;
// Dummy node to help establish the head of DLL TreeNode dummy =new TreeNode(-1);
prev = dummy;
// Helper recursive function inorderTraversal(root);
// The right of the dummy node will be the head of our DLL TreeNode head = dummy.right;
if (head !=null) head.left=null; // Head's left pointer must be nullreturn head;
}
// Recursive in-order traversalprivatevoidinorderTraversal(TreeNode curr) {
if (curr ==null) return;
// Left subtree inorderTraversal(curr.left);
// Current node manipulation prev.right= curr; // Connect previous node's right to current node curr.left= prev; // Connect current node's left to previous node prev = curr; // Move prev pointer to current node// Right subtree inorderTraversal(curr.right);
}
// Utility method to print DLLpublicvoidprintDLL(TreeNode head) {
TreeNode temp = head;
while (temp !=null) {
System.out.print(temp.val+" <-> ");
temp = temp.right;
}
System.out.println("null");
}
}
classSolution:
def __init__(self):
self.prev =None# Pointer to track previous nodedefBTtoDLL(self, root):
ifnot root:
returnNone# Dummy node to help establish the head of DLL dummy = self.TreeNode(-1)
self.prev = dummy
# Helper recursive function self.inorderTraversal(root)
# The right of the dummy node will be the head of our DLL head = dummy.right
if head:
head.left =None# Head's left pointer must be nullreturn head
definorderTraversal(self, curr):
ifnot curr:
return# Left subtree self.inorderTraversal(curr.left)
# Current node manipulation self.prev.right = curr # Connect previous node's right to current node curr.left = self.prev # Connect current node's left to previous node self.prev = curr # Move prev pointer to current node# Right subtree self.inorderTraversal(curr.right)
# Utility method to print DLLdefprintDLL(self, head):
temp = head
while temp:
print(temp.val, end=" <-> ")
temp = temp.right
print("null")
⏰ Time complexity: O(n) because we traverse each node of the binary tree exactly once.
🧺 Space complexity: O(h) where h is the height of the binary tree due to the recursive call stack.
Method 2 - Update inorder predecessor and successor#
The solution involves two straightforward steps:
Fix Left Pointers: Perform an in-order traversal on the binary tree to update the left pointers of each node. During the traversal, maintain a reference to the previously visited node and set the left pointer to point to it. This establishes the preceding relationships in the Doubly Linked List (DLL).
Fix Right Pointers: Starting from the rightmost node (the last node in the DLL), traverse the left pointers linearly from end to start. As you move through the nodes, update the right pointers to point to the previously visited node, completing the DLL connections.
classSolution {
// Fix left pointers using in-order traversalprivate TreeNode fixPrevPtr(TreeNode root) {
TreeNode prev =null;
if (root !=null) {
// Recur for the left subtree prev = fixPrevPtr(root.left);
// Set left pointer to the previous node root.left= prev;
// Update previous node to current node prev = root;
// Recur for the right subtree prev = fixPrevPtr(root.right);
}
return prev;
}
// Fix right pointers using the already fixed left pointersprivate TreeNode fixNextPtr(TreeNode root) {
// Start from the rightmost nodewhile (root.right!=null) {
root = root.right;
}
// Traverse from rightmost to leftmost TreeNode prev =null;
while (root !=null) {
root.right= prev; // Fix right pointer prev = root; // Move prev pointer root = root.left; // Move to the previous node in DLL }
return prev; // Return the head of the DLL }
// Convert a Binary Tree to Doubly Linked Listpublic TreeNode BTtoDLL(TreeNode root) {
if (root ==null) returnnull;
// Step 1: Fix left pointers fixPrevPtr(root);
// Step 2: Fix right pointersreturn fixNextPtr(root); // The returned node is now the head of DLL }
// Utility to print the DLLpublicvoidprintDLL(TreeNode head) {
TreeNode temp = head;
while (temp !=null) {
System.out.print(temp.val+" <-> ");
temp = temp.right;
}
System.out.println("null");
}
}
classSolution:
# Fix left pointers using in-order traversaldeffixPrevPtr(self, root):
prev =None stack = [] # Stack for in-order traversal current = root
while stack or current:
# Traverse the left subtreewhile current:
stack.append(current)
current = current.left
# Visit the node current = stack.pop()
current.left = prev # Fix left pointer prev = current # Update prev node# Traverse the right subtree current = current.right
return prev
# Fix right pointers using the already fixed left pointersdeffixNextPtr(self, root):
# Move to the rightmost nodewhile root.right:
root = root.right
prev =None# Traverse from rightmost to leftmostwhile root:
root.right = prev # Fix right pointer prev = root # Update prev pointer root = root.left # Move to the previous node in DLLreturn prev # Return the head of the DLL# Convert a Binary Tree to Doubly Linked ListdefBTtoDLL(self, root):
ifnot root:
returnNone# Step 1: Fix left pointers self.fixPrevPtr(root)
# Step 2: Fix right pointersreturn self.fixNextPtr(root) # The returned node is the head of DLL# Utility function to print the DLLdefprintDLL(self, head):
temp = head
while temp:
print(temp.data, end=" <-> ")
temp = temp.right
print("null")
This involves an in-order traversal of the binary tree which visits each node exactly once, which takes O(n).
After the left pointers are fixed, traversing the nodes linearly via left pointers (from the last node to the first) also involves visiting all the nodes once. This takes O(n).
🧺 Space complexity: O(h). The space complexity of recursion (or iterative traversal) comes into play due to the call stack.