Given a binary search tree, print the elements in-order iteratively without using recursion.
Note:
Before you attempt this problem, you might want to try coding a pre-order traversal iterative solution first, because it is easier. On the other hand, coding a post-order iterative version is a challenge. See my post: Binary Tree Post-Order Traversal Iterative Solution for more details and an in-depth analysis of the problem.
We know the elements can be printed in-order easily using recursion, as follow:
1
2
3
4
5
6
|
void
in_order_traversal
(
BinaryTree *
p
)
{
if
(
!
p
)
return
;
in_order_traversal
(
p
->
left
)
;
cout
<<
p
->
data
;
in_order_traversal
(
p
->
right
)
;
}
|
Excessive recursive function calls may cause memory to run out of stack space and extra overhead. Since the depth of a balanced binary search tree is about lg(n), you might not worry about running out of stack space, even when you have a million of elements. But what if the tree is not balanced? Then you are asking for trouble, because in the worst case the height of the tree may go up to n. If that is the case, stack space will eventually run out and your program will crash.
To solve this issue, we need to develop an iterative solution. The idea is easy, we need a stack to store previous nodes, and a visited flag for each node is needed to record if the node has been visited before. When a node is traversed for the second time, its value will be printed. After its value is printed, we push its right child and continue from there.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
void
in_order_traversal_iterative
(
BinaryTree *
root
)
{
stack
<
BinaryTree*
>
s
;
s
.
push
(
root
)
;
while
(
!
s
.
empty
(
)
)
{
BinaryTree *
top
=
s
.
top
(
)
;
if
(
top
!=
NULL
)
{
if
(
!
top
->
visited
)
{
s
.
push
(
top
->
left
)
;
}
else
{
cout
<<
top
->
data
<<
" "
;
s
.
pop
(
)
;
s
.
push
(
top
->
right
)
;
}
}
else
{
s
.
pop
(
)
;
if
(
!
s
.
empty
(
)
)
s
.
top
(
)
->
visited
=
true
;
}
}
}
|
Alternative Solution:
The above solution requires modification to the original BST data structure (ie, adding a visited flag). The other solution which doesn’t modify the original structure is with the help of a current pointer in addition of a stack.
First, the current pointer is initialized to the root. Keep traversing to its left child while pushing visited nodes onto the stack. When you reach a NULL node (ie, you’ve reached a leaf node), you would pop off an element from the stack and set it to current. Now is the time to print current’s value. Then, current is set to its right child and repeat the process again. When the stack is empty, this means you’re done printing.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
void
in_order_traversal_iterative
(
BinaryTree *
root
)
{
stack
<
BinaryTree*
>
s
;
BinaryTree *
current
=
root
;
bool
done
=
false
;
while
(
!
done
)
{
if
(
current
)
{
s
.
push
(
current
)
;
current
=
current
->
left
;
}
else
{
if
(
s
.
empty
(
)
)
{
done
=
true
;
}
else
{
current
=
s
.
top
(
)
;
s
.
pop
(
)
;
cout
<<
current
->
data
<<
" "
;
current
=
current
->
right
;
}
}
}
}
|
We can even do better by refactoring the above code. The refactoring relies on one important observation:
Why this is true? To prove this, we assume the opposite, that is: the last traversed node has a right child. This is certainly incorrect, as in-order traversal would have to traverse its right child next before the traversal is done. Since this is incorrect, the last traversed node must not have a right child by contradiction.
Below is the refactored code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
void
in_order_traversal_iterative
(
BinaryTree *
root
)
{
stack
<
BinaryTree*
>
s
;
BinaryTree *
current
=
root
;
while
(
!
s
.
empty
(
)
||
current
)
{
if
(
current
)
{
s
.
push
(
current
)
;
current
=
current
->
left
;
}
else
{
current
=
s
.
top
(
)
;
s
.
pop
(
)
;
cout
<<
current
->
data
<<
" "
;
current
=
current
->
right
;
}
}
}
|
Further Thoughts:
The above solutions require the help of a stack to do in-order traversal. Is it possible to do in-order traversal without a stack?
The answer is yes, it’s possible. There’s 2 possible ways that I know of:
1 public class Solution { 2 public ArrayList<Integer> inorderTraversal(TreeNode root) { 3 Stack<TreeNode> st = new Stack<TreeNode>(); 4 ArrayList<Integer> result = new ArrayList<Integer>(); 5 if(root == null) return result; 6 boolean fin = false; 7 while(!fin){ 8 if(root != null){ 9 st.push(root); 10 root = root.left; 11 }else{ 12 if(st.size() == 0){ 13 fin = true; 14 }else{ 15 root = st.pop(); 16 result.add(root.val); 17 root = root.right; 18 } 19 } 20 } 21 return result; 22 } 23 }
这个代码是错误的:
1 public List<Integer> inorderTraversal(TreeNode root) { 2 // write your code here 3 LinkedList<TreeNode> stack = new LinkedList<TreeNode> (); //stack 4 List<Integer> result = new ArrayList<Integer> (); 5 if(root == null) return result; 6 stack.push(root); 7 while(!stack.isEmpty()){ 8 TreeNode tmp = stack.peek(); 9 if(tmp.left != null) stack.push(tmp.left); 10 else{ 11 tmp = stack.pop(); 12 result.add(tmp.val); 13 if(tmp.right != null) stack.push(tmp.right); 14 } 15 } 16 return result; 17 }
会在最后一个root 和其left leaf之间无限循环。