1.事情起因
刷力扣到了二叉树遍历算法部分,递归方法实在太简单了,对应三种前中后序为:
- 前:根左右
- 中:左根右
- 后:左右根
但是发现时间复杂度很高,递归开辟隐式栈空间导致的,所以研究了下使用“迭代”方法,自己显示开辟一个栈空间来实现,结果不错,很大程度提高了计算速度。我是一名Unity程序,所以使用C#。
2.二叉树遍历通过迭代实现
三种前中后序迭代实现方式思路均略有不同,所以在此记录下来。
2.1 前序遍历(迭代法)
思路(根左右):
- 开辟一个辅助栈空间,根入栈,顶出栈进行操作输出,右左入栈(为什么?因为右左入,左右出,符合前序的顺序)。以此遍历直到空栈结束。
public IList<int> PreorderTraversal(TreeNode root)
{
IList<int> t = new List<int>();
if (root == null)
return t;
Stack<TreeNode> s = new Stack<TreeNode>();
s.Push(root);
while (s.Count > 0)
{
TreeNode n = s.Pop();
t.Add(n.val);
if (n.right != null)
s.Push(n.right);
if (n.left != null)
s.Push(n.left);
}
return t;
}
2.2 中序遍历(迭代法)
思路(左根右):
- 中序遍历并非简单调整代码顺序就能实现,因为遍历顺序与操作输出的顺序不一致,所以需采用自顶向下找最左叶子结点,然后向上,之后再出栈处理右节点。
public IList<int> PrecenterTraversal(TreeNode root)
{
IList<int> t = new List<int>();
if (root == null)
return t;
Stack<TreeNode> s = new Stack<TreeNode>();
s.Push(root);
TreeNode r = root;
while (r != null && s.Count > 0)
{
if (r != null)
{
s.Push(r);
r = r.left;
}
else
{
r = s.Pop();
t.Add(r.val);
r = r.right;
}
}
return t;
}
2.3 后序遍历(迭代法)
思路(左右根):
- 后序遍历可以在前序遍历的基础之上变种,前序入栈操作顺序为根右左,调整为根左右,则输出顺序就是根右左,再对输出结果Reverse,就变成目标的左右根顺序了。
- 重申一下:根右左、根左右(这是入栈顺序),对应出栈顺序为根左右、根右左(这是操作输出顺序),那么反转根右左,就变成了左右根。
public IList<int> PostorderTraversal(TreeNode root)
{
List<int> t = new List<int>();
if (root == null)
return t;
Stack<TreeNode> s = new Stack<TreeNode>();
s.Push(root);
while (s.Count > 0)
{
TreeNode n = s.Pop();
t.Add(n.val);
if (n.left != null)
s.Push(n.left);
if (n.right != null)
s.Push(n.right);
}
t.Reverse();
return t;
}
3.优化结果
- 从力扣提交记录上看,耗时排名上升幅度很大
递归 迭代 耗时排名 战胜14% 战胜98%