前序遍历
前序遍历:中 -> 左子树 -> 右子树
非递归的遍历-stack
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (null == root) {
return res;
}
LinkedList<TreeNode> stack = new LinkedList<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
res.add(node.val);
if (null != node.right) {
stack.push(node.right);
}
if (null != node.left) {
stack.push(node.left);
}
}
return res;
}
morris
空间复杂度为O(1)
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if (root == null) {
return res;
}
TreeNode cur = root;
while (cur != null) {
// 左子树不为null,优先处理
if (null != cur.left) {
TreeNode leftMaxRight = cur.left;
while (leftMaxRight.right != null && leftMaxRight.right != cur) {
leftMaxRight = leftMaxRight.right;
}
// leftMaxRight为叶子结点,right==null表示 要续上;否则表示 已经处理完,要恢复
if (leftMaxRight.right == null) {
res.add(cur.val);
// 续上 连接,指向中序排序下一个结点:leftMaxRight若为左子树,则right=parent; 若为右子树,则right = 所在树的root.root
leftMaxRight.right = cur;
cur = cur.left;
continue;
} else {
// leftMaxRight为叶子结点,将续上的连接 恢复null值
leftMaxRight.right = null;
}
} else {
// 1) 非叶子结点,左子树为null,直接添加cur,再处理其右子树
// 2) 叶子结点,右子树 为 续上 的连接,指向中序排序下一个结点
res.add(cur.val);
}
// 1)cur及其左子树 处理完后,处理右子树
// 2)cur为叶子节点时,cur.right为 其 中序 遍历的 下一个节点
cur = cur.right;
}
return res;
}
遍历时续上的连接 如下所示,指向 中序遍历 的下一个结点,node5.right=node1, node4.right = node2
1: 5->1, 输出1,进入2
2: 4->2, 输出2,进入4
4: 输出4,进入2
2: 断开 4->2, 进入5
5:输出5,进入1
1: 断开5->1, 进入3
3: 6->3, 输出3,进入6
6: 输出6,进入3
3: 断开6->3, 进入7
7: 输出7
最终序列为:1、2、4、5、3、6、7
力扣上的题目:
https://leetcode.cn/problems/binary-tree-preorder-traversal/solutions/461821/er-cha-shu-de-qian-xu-bian-li-by-leetcode-solution/?company_slug=meituan
后序遍历
左子树 -> 右子树 -> root
morris
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (null == root) {
return res;
}
TreeNode cur = root;
while (null != cur) {
if (null != cur.left) {
TreeNode leftMaxRight = cur.left;
while (leftMaxRight.right != null && leftMaxRight.right != cur) {
leftMaxRight = leftMaxRight.right;
}
if (leftMaxRight.right == null) {
// 续上, 中序遍历的下一个结点
leftMaxRight.right = cur;
cur = cur.left;
continue;
} else {
// 将续上的干掉
leftMaxRight.right = null;
// 叶子结点 在 第2次遍历到其parent时,才会处理
addNodeRight(res, cur.left);
}
}
cur = cur.right;
}
// 处理最后的右子树横线
addNodeRight(res, root);
return res;
}
// 处理node开始的右子树 线
public void addNodeRight(List<Integer> res, TreeNode node) {
int left = res.size();
while (null != node) {
res.add(node.val);
node = node.right;
}
int right = res.size() - 1;
// left为第一个插入位置,right为最后插入位置
// 将left和right范围内 倒转
while (left < right) {
int tmp = res.get(left);
res.set(left, res.get(right));
res.set(right, tmp);
left++;
right--;
}
}
leetcode题目地址:https://leetcode.cn/problems/binary-tree-postorder-traversal/submissions/?company_slug=meituan
中序遍历-morris
参考前序遍历
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if (root == null) {
return res;
}
TreeNode cur = root;
while (cur != null) {
if (null != cur.left) {
TreeNode leftMaxRight = cur.left;
while (leftMaxRight.right != null && leftMaxRight.right != cur) {
leftMaxRight = leftMaxRight.right;
}
if (leftMaxRight.right == null) {
leftMaxRight.right = cur;
cur = cur.left;
continue;
} else {
// 前序遍历 cur在if放入 res;中序遍历在else里面加入
res.add(cur.val);
leftMaxRight.right = null;
}
} else {
res.add(cur.val);
}
cur = cur.right;
}
return res;
}