题目
给定一个二叉树,返回它的 前序 遍历。
给定一个二叉树,返回它的 中序 遍历。
给定一个二叉树,返回它的 后序 遍历。
但是很明显,如果是递归写法,十分简单,不会是中等难度了
题上也明确表示了,写 迭代算法
public List<Integer> preorderTraversal(TreeNode root) {
}
ps : 这三道题的题号分别是144,94,145
什么是二叉树
百度直达链接 二叉树
前序、中序、后序
- 前序: 先输出根节点,然后输出左孩子节点,然后输出右孩子节点。对于树中的每一颗子树都一样
- 中序: 先输入左孩子节点,然后输入根节点,再输出右孩子节点
- 后续: 先输出左孩子节点,再输出右孩子节点,然后输出根节点
其实所谓的某序,指的就是根节点的顺序。这样记的话就很容易记得了。
解题思路
首先需要一个数据结构来存取我们的树节点。而且需要的是存取比较方便的数据结构,那么就可以是队列或者栈。 可以根据实际情况选择。
前序遍历
根 - 左- 右的顺序。 先添加root节点到存储的数据结构中。
根节点加入到链表中,然后当链表不为空的时候,遍历栈或者队列,取出根节点,加入到结果链表中。往链表放入根节点的两个孩子节点中不为空的节点。 下一次循环:取出栈或者队列中的节点,此时必须取出“上一次取出节点”的左节点。 。
此时进行思考 :我们到底是选用栈还是队列?
不论栈还是队列,都需要进行判断
while( ! stack or queue.isEmpty()) {
}
1.假设选用队列,遍历完了根节点,然后选择加入根节点的左右孩子节点,应该先加左节点,后加右节点(因为队列的属性是FIFO,这样填充才能保证下一次首先取出来的是左孩子)。
看起来似乎没有问题,但是继续往下走,第二次进来的时候先取出左节点,然后就会往队列中加入它的左右孩子。然后下一次进入循环,并不是取出上一个节点的左右孩子,而是取出了它的兄弟节点(就是跟他同一层的另一个节点)。 这样就不符合前序遍历规则了。
2.假设选用栈,此时加入孩子节点的顺序就要换一下。 先加入根节点的右孩子节点,然后加入根节点的左孩子节点。
这样才可以保证每一次取出节点时取出来的是左孩子节点。
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> ans; = new ArrayList<>();
Deque<TreeNode> stack = new ArrayDeque<>();
//特殊判断
if(root == null)
return ans;
//加入根节点
stack.push(root);
while (! stack.isEmpty()) {
TreeNode cur = stack.pop();
ans.add(cur.val);
//先加入不为空的右孩子
if(cur.right != null){
stack.push(cur.right);
}
//加入不为空的左孩子
if(cur.left != null)
stack.push(cur.left);
}
return ans;
}
中序遍历
时间关系,思路其实是一样的,建议画图,比较清晰明了
直接贴代码:
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> ans = new ArrayList<>();
Deque<TreeNode> stack = new ArrayDeque<>();
while (root != null || !stack.isEmpty()) {
//一直添加左节点,循环结束时,root是左子节点
while (root != null){
//第一次进来 加入root节点到stack
stack.push(root);
root = root.left;
}
//左子节点赋给root。每次出来一个左节点。
//就需要把他的右子树加入到结果中。因为他如果作为一个root节点,那么他的左子树肯定都进入stack了
//根据中序遍历,规则,现在就需要把右子树加进来。
root = stack.pop();
ans.add(root.val);
//将root置换为当前节点的右节点。 对当前节点的右子树进行中序遍历
root = root.right;
}
return ans;
}
}
后序遍历
class Solution {
public List<Integer> postorderTraversal(TreeNode root){
LinkedList<Integer> ans = new LinkedList<>();
//特殊判断
if(root == null)
return ans;
Deque<TreeNode> stack = new ArrayDeque<>();
//加入根节点,既然根节点第一个出来,那顺序就是反的。可以采取头插法,这样最终的顺序就是正确的
stack.push(root);
while (!stack.isEmpty()) {
TreeNode cur = stack.pop();
//头插法;
ans.addFirst(cur.val);
//加入左孩子
if(cur.left != null) {
stack.push(cur.left);
}
//加入右孩子
if(cur.right != null){
stack.push(cur.right);
}
}
return ans;
}
}