前序遍历二叉树,额外空间复杂度为O(1),条件搜索, morris遍历
思路:
-
来到的当前节点记为 cur, 1.如果cur左节点为null,cur向右移动 cur = cur.right 2.如果cur左节点不为null,找到左子树上最右的节点,记为mostRight 1)如果mostRight的右节点指向null,让其指向cur,cur向左移动 cur = cur.left 2)如果mostRight的右节点指向cur,让其指向null,cur向右移动 cur = cur.right
相比于递归遍历每个节点遍历3次,morris遍历有左子树的每个节点遍历了2次,没有左子树的节点只遍历了一次
即 :在cur左子树遍历完了,会返回到cur,再次遍历,但是发现cur左子树最右节点mostRight已经被赋值为cur。
便恢复mostRight = null;走cur的右子数。这样实现遍历2次。
下面给出代码(来自leetcode):
public class MorrisSearch {
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new LinkedList<>();
TreeNode cur = root;
TreeNode mostRight;
while (cur!=null){
mostRight = cur.left;
if(mostRight !=null){ //判断cur是否有左节点
//当cur左子树的最右节点不为空,且未指向过cur 依次找到最右节点
while (mostRight.right!=null && mostRight.right!=cur){
mostRight = mostRight.right;
}
//当最右节点为空,让其指向cur 这一步是为了第二次来到cur节点,可以走cur右节点
if(mostRight.right == null){
mostRight.right = cur;
list.add(cur.val); //往左走的时候添加该节点·!!!!
cur = cur.left;
continue;
}else { //不为空的时候说明 是第二次来到该节点了 恢复该节点指向空
mostRight.right=null;
}
}else{ //没有左节点的时候,添加该节点·!!!!
list.add(cur.val);
}
cur= cur.right;
}
return list;
}
}