Morris树时间复杂度O(N)空间复杂度O(1)

Morris算法简述:

遍历到每一个节点的时候,

1、如果当前节点有左孩子,则将当前节点做孩子的最右孩子指向自己;

2、如果当前节点没有左孩子,则跳向右边孩子;

3、如果当前节点左孩子最右节点指向自己,则断开,跳向下一个节点

public static void morris(TreeNode head){
        if (head==null) return;
        TreeNode cur=head;
        TreeNode MostRightNode;
        while(cur!=null){
            MostRightNode=cur.left;
            if (MostRightNode!=null){
            //找到左孩子最右边孩子
                while(MostRightNode.right!=null&&MostRightNode.right!=cur){
                    MostRightNode=MostRightNode.right;
                }
                if (MostRightNode.right==null){
                    //如果有左孩子,且第一次遍历会到这个地方
                    MostRightNode.right=cur;
                    cur=cur.left;
                    continue;
                }else {
                    //如果有左孩子,且第二次遍历会到这个地方
                    MostRightNode.right=null;
                }
            }
        //没有左孩子或者是第二次到达当前节点都会到这个地方
            cur=cur.right;
        }
    }

以当前树为例子

遍历顺序就是ABDBEAC,有左孩子的节点都会遍历两遍

所以前序遍历就是当第一次到达当前节点的时候进行打印。

中序遍历就是当第二次遍历当前节点的时候进行打印

后序遍历比较麻烦,当第二次遍历当前节点的时候,需要将左孩子的节点逆序打印,如下面

最后将根节点右边逆序打印

public List<Integer> postorderTraversal(TreeNode root) {
        LinkedList<Integer> ans = new LinkedList<>();
        if(root==null)return ans;
        // LinkedList<TreeNode> stack = new LinkedList<>();
        // LinkedList<TreeNode> stack1 = new LinkedList<>();
        // stack.push(root);
        // while(!stack.isEmpty()){
        //     TreeNode cur=stack.pop();
        //     stack1.push(cur);
        //     if(cur.right!=null){
        //         stack.push(cur.right);
        //     }
        //     if(cur.left!=null){
        //         stack.push(cur.left);
        //     }
        // }
        // while(!stack1.isEmpty()){
        //     ans.add(stack1.pop().val);
        // }
        // return ans;
        //morris
        TreeNode cur=root;
        while(cur!=null){
            //先找到左孩子最右节点
            TreeNode mostRightNode=cur.left;
            if(mostRightNode!=null){
                while(mostRightNode.right!=null&&mostRightNode.right!=cur){
                    mostRightNode=mostRightNode.right;
                }
                if(mostRightNode.right==null){
                    //第一次到达当前节点
                    mostRightNode.right=cur;
                    cur=cur.left;
                    continue;
                }
                if(mostRightNode.right==cur){
                    //第二次到达当前节点
                    mostRightNode.right=null;
                    print(cur.left,ans);
                }
            }
            cur=cur.right;
        }
        print(root,ans);
        return ans;
    }
         private static  void print(TreeNode node,LinkedList<Integer> ans){
        TreeNode newHead = reverse(node);
        TreeNode point=newHead;
        while (point!=null){
            ans.add(point.val);
            point=point.right;
        }
        reverse(newHead);
    }
    private static TreeNode reverse(TreeNode head){
        TreeNode newHead=head;
        TreeNode point;
        while (head.right!=null){
            point=head.right;
            head.right=point.right;
            point.right=newHead;
            newHead=point;
        }
        return newHead;
    }

是否是BST

以上面的树为例,当第二次来到当前节点的时候左树的所有节点已经遍历过了,此时因为是从左孩子最右节点指过来的,所以上一个节点代表的是左孩子上最大的值,如果是一个普通的没有左孩子的节点或者是叶子的话,遍历顺序都是右边,所以右边一定要比上一个节点更大。

public static boolean isBST(Node head) {
		if (head == null) {
			return true;
		}
		Node cur = head;
		Node mostRight = null;
		Integer pre = null;
		boolean ans = true;
		while (cur != null) {
			mostRight = cur.left;
			if (mostRight != null) {
				while (mostRight.right != null && mostRight.right != cur) {
					mostRight = mostRight.right;
				}
				if (mostRight.right == null) {
					mostRight.right = cur;
					cur = cur.left;
					continue;
				} else {
					mostRight.right = null;
				}
			}
        //当每次遍历到叶子节点或者是第二次来到当前节点,都需要判断当前节点是不是比上次保留的值大。
			if (pre != null && pre >= cur.value) {
				ans = false;
			}
			pre = cur.value;
			cur = cur.right;
		}
		return ans;
	}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值