Algorithm -- Binary Tree to Linked List (In-place)
Flatten a Binary Tree to Linked List, with preorder, inorder, or postorder. Implement the algorithm in place.
I’ll use 3 different methods to implement each order. They are [recursion with TreeNode, void recursion, iteration]
.
I’ll remember this problem for I had lost a great opportunity without solving it.
And also remember, don’t reference only one or even only two solutions when cracking LeetCode. And an alternative as well as most essencial point is cracking it with your own codes.
Flatten Binary Tree to Linked List is the preorder
problem.
Void Recursion
Inorder
First, let’s talk about inorder!!!
This is the simplest method. We use similar codes while traversing a Binary Tree with void recursion. Assuming no requirement of in place implement. Then we can simply append every traversed TreeNode in the tail of a Linked List.
e.g. Inorder version without requirement of in place, which takes a static LinkedList as result.
static LinkedList<TreeNode> list = new LinkedList<TreeNode>();
void flattenInorder(TreeNode root) {
if (root == null) return;
falttenInorder(root.left);
list.add(root);
flattenInorder(root.right);
}
Then, the list is the result, you can treat it as a cache which stores the output of inorder traverse while System.out.println(root.val);
is being used instead of list.add(root)
.
Now, let’s compare the above with the in place algorithm, which takes constant (two: prev & head) number of variables.
static TreeNode prev = null;
static TreeNode head = null;
void flattenInorder(TreeNode root) {
if (root == null) return;
flattenInorder(root.left);
if (head == null) head = root;
if (prev != null) {
prev.right = root;
}
root.left = null;
prev = root;
flattenInorder(root.right);
}
Then, the head is pointing at the begining of the flattened Linked List.
If you do not like to use static
, you can create another function void flattenInorder(TreeNode root, TreeNode[] prev, TreeNode[] head
with prev[0] and head[0] for passing reference of previous node and head node of Linked List.
TreeNode flattenInorder(TreeNode root) {
TreeNode[] prev = new TreeNode[1];
TreeNode[] head = new TreeNode[1];
flattenInorder(root, prev, head);
return head[0];
}
void flattenInorder(TreeNode root, TreeNode[] prev, TreeNode[] head) {
if (root == null) return;
flattenInorder(root.left, prev, head);
root.left = null;
if (prev[0] != null) {
prev[0].right = root;
}
prev[0] = root;
if (head[0] == null) {
head[0] = root;
}
flattenInorder(root.right, prev, head);
}
Preorder
Like the simple tree traverse, we can use a similar code structure to flatten a Binary Tree into Linked List with preorder.
- As the root of BT is the head of LL, we do not need to set head pointer.
-
As the right pointer of each node will be set before recusion called on rightBranch, so we need to set a variable to mark rightBranch in every recursion.
void flattenPreorder(TreeNode root, TreeNode[] prev) { if (root == null) return; TreeNode rightBranch = root.right; if (prev[0] != null) { prev[0].right = root; } prev[0] = root; flattenPreorder(root.left, prev); root.left = null; flattenPreorder(rightBranch, prev); }
Postorder
void flattenPostorder(TreeNode root, TreeNode[] prev, TreeNode[] head) {
if (root == null) return;
flattenPostorder(root.left, prev, head);
if (head[0] == null) {
head[0] = root;
}
flattenPostorder(root.right, prev, head);
root.left = null;
root.right = null;
if (prev[0] != null) {
prev[0].right = root;
}
prev[0] = root;
}
From the 3 different order of void recursion, we can see that:
if (prev[0] != null) {
prev[0].right = root;
}
prev[0] = root;
Theses code snip is similar to the print current node sentence in tree traverse: println(root.val);
.
Iteration
The iteration traverse of Binary Tree is commonly implemented with an assistant Stack
Inorder
TreeNode flattenInorder(TreeNode root) {
TreeNode head = null;
TreeNode last = null;
while (root != null) {
if (root.left != null) {
TreeNode pre = root.left;
while (pre.right != null) {
pre = pre.right;
}
pre.right = root;
pre = pre.right;
root = root.left;
pre.left = null;
if (last != null) {
last.right = root;
}
} else {
if (head == null) head = root;
last = root;
root = root.right;
}
}
return head;
}
TreeNode pre
is used to mark the previous node of the root when root’s left child is existed;TreeNode last
is used to traverse Linked List afterhead
has been set.
This shows inorder iteration of flatten, the data stream is labled by (index) in colors.
Preorder
The preorder iteration is obviously the most simplest way to flatten a Binary Tree to a Linked List.
void flattenInorder(TreeNode root) {
while (root != null) {
if (root.left != null) {
TreeNode prev = root.left;
while (prev.right != null) {
prev = prev.right;
}
prev.right = root.right;
root.right = root.left;
root.left = null;
}
root = root.right;
}
}
Postorder
How?
Recursion with Return Value
The signature of recursion with return value is TreeNode flatten(TreeNode root) { ... /* recursion */ ... }
.
The tricky part is we are attempting to use this single one recursion to impelment the entire flatten function. So we need to reture the head of Linked List. It will be relatively easier for preorder. But harder for the other two types.
Inorder
Actually another simple problem could be solved by Divide-and-Conquer, just need to reserve the left pointer while recursion rather than set null
.
Hinted by in place convert a Binary Tree to Doubly Linked List
This version requires to
-
track left pointer while recursion;
-
reset the head of Linked List and set left pointer to null after recursion.
TreeNode flattenInorder(TreeNode root) { // build inorder doubly linked list root = flattenInorderHelper(root); // set head while (root.left != null) { root = root.left; } // set left null TreeNode p = root.right; while (p != null) { p.left = null; p = p.right; } return root; } TreeNode flattenInorderHelper(TreeNode root) { if (root == null) return null; if (root.left != null) { TreeNode left = flattenInorderHelper(root.left); while (left.right != null) { left = left.right; } left.right = root; root.left = left; } if (root.right != null) { TreeNode right = flattenInorderHelper(root.right); while (right.left != null) { right = right.left; } right.left = root; root.right = right; } return root; }
Preorder
This non-trivil version is too tricky for me.
TreeNode flattenPreorder(TreeNode root) {
if (root == null) return null;
TreeNode tail = root;
TreeNode right = root.right;
if (root.lleft != null) {
tail = flattenPreorder(root.left);
root.right = root.left;
tail.right = right;
root.left = null;
}
if (right != null) {
tail = flattenPreorder(right);
}
return tail;
}
or
TreeNode flattenPreorder(TreeNode root) {
if (root == null) return null;
TreeNode rightTree = root.right;
if (root.left != null) {
root.right = null;
root.left = null;
root = flattenPreorder(root.right);
}
if (rightTree != null) {
root.right = rightTree;
root = flattenPreorder(root.right);
}
return root;
}
Postorder
This is my own trivial version of postorder followed by the inorder version.
Two pointer should be taken care for:
-
Set
root.right = null
to avoid infinite loop in recursion; -
When linking right pointer, if
root.right == null
, the next (right) pointer of last node (most right node in left branch) should be linked to root directly.TreeNode flattenPostorder(TreeNode root) { root = flattenPostorderHelper(root); // set head while (root.left != null) { root = root.left; } TreeNode p = root.right; while (p != null) { p.left = null; p = p.right; } return root; } TreeNode flattenPostorderHelper(TreeNode root) { if (root == null) return null; TreeNode leftTree = root.left; TreeNode rightTree = root.right; root.right = null; if (leftTree != null) { leftTree = flattenPostorderHelper(leftTree); } if (rightTree != null) { rightTree = flattenPostorderHelper(rightTree); } if (leftTree != null) { while (leftTree.right != null) { leftTree = leftTree.right; } } if (rightTree != null) { TreeNode rightFirst = rightTree; while (rightFirst.left != null) { rightFirst = rightFirst.left; } leftTree.right = rightFirst; while (rightTree.right != null) { rightTree = rightTree.right; } rightTree.right = root; } else { if (leftTree != null) leftTree.right = root; } return root; }
Reference
1. http://www.geeksforgeeks.org/in-place-convert-a-given-binary-tree-to-doubly-linked-list/
2. http://www.geeksforgeeks.org/convert-a-given-binary-tree-to-doubly-linked-list-set-2/
3. http://www.geeksforgeeks.org/convert-given-binary-tree-doubly-linked-list-set-3/
4. http://leetcode.com/2010/11/convert-binary-search-tree-bst-to.html
5. http://cslibrary.stanford.edu/109/TreeListRecursion.html
6. http://www.geeksforgeeks.org/in-place-convert-a-given-binary-tree-to-doubly-linked-list/
7. http://n00tc0d3r.blogspot.com/2013/03/flatten-binary-tree-to-linked-list-in.html