Morris In-order traverse二叉树Recover BST,空间优化

本文探讨了二叉树的遍历方法,包括递归、栈和队列方式,重点介绍了Morris中序遍历算法,该算法通过以时间换空间的方式实现了O(1)的空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 一般遍历二叉树要么使用递归,要么借助于栈或队列。遍历的时间复杂度为O(n),空间复杂度也为O(n)
  • 在LeetCode第99题Recover Binary Search Tree中,使用栈的解答较为简便:
// 中序遍历
	public void recoverTreex(TreeNode root) {
		if(root == null) return;
        TreeNode prev = null, first = null, second = null;
  	    Stack<TreeNode> stack = new Stack<>();
        while(root != null || !stack.isEmpty()){
        	while(root!=null){
        		stack.push(root);
        		root = root.left;
        	}
        	root = stack.pop();
        	if(prev != null && root.val < prev.val){
        		if(first == null) first = prev; //存第一个反序对的前一个节点 
        		second = root;//存第二个反序对的后一个节点
        	}
        	prev = root;
        	root = root.right;
        }
    	int tmp = second.val;
    	second.val = first.val;
    	first.val = tmp;
    }
  • Follow up:
    A solution using O(n) space is pretty straight forward.
    Could you devise a constant space solution?能否使用O(1)空间复杂度解决问题呢?——Morris中序遍历

  • Morris算法——以时间换空间

  1. 整个遍历过程都是按照二叉树递归遍历的思路进行。以时间换空间,对路径进行了重复的访问。
  2. 利用了叶子节点的空指针域,遍历过程,先利用空指针保存以后要到达的路径,
  3. 使用完成之后再恢复成空指针。
  4. 只是在输出节点信息(即访问节点信息)处有不同。

中序遍历保存节点

public List<Integer> inorderTraversal(TreeNode root) {
	    	List<Integer> inorder = new ArrayList<>();
	    	TreeNode pnode = root, tmp = null;
	    	while(pnode != null){
	    		if(pnode.left == null){
	    			inorder.add(pnode.val);
	    			pnode = pnode.right; //总是指向中序的下一个节点
	    		} else{
	    			tmp = pnode.left;
	    			// 找到左子树的最右子节点
	    			while(tmp.right != null && tmp.right != pnode)
	    				tmp = tmp.right;
	    			if(tmp.right == null){ //第一次遍历 == null
	    				tmp.right = pnode; // 叶子节点的右孩子记录将要遍历的顺序
	    				pnode = pnode.left;
	    			} else{ //第二次遍历 == pnode
	    				inorder.add(pnode.val); 
	    				tmp.right = null; //恢复为空节点
	    				pnode = pnode.right;
	    			}
	    		}
	    	}
	    	return inorder;
	  }

99题解法

public void recoverTree(TreeNode pnode) {
		if(pnode == null) return;
		TreeNode prev = null, first = null, second = null;
		TreeNode tmp = null;
		while(pnode != null){
			if(pnode.left == null){
				if(prev != null && pnode.val < prev.val){
		     		if(first == null) first = prev; //存第一个反序对的前一个节点 
		     		second = pnode;//存第二个反序对的后一个节点
		     	}
				prev = pnode;
				pnode = pnode.right;
			} else{
				tmp = pnode.left;
				// 找到左子树的最右子节点
				while(tmp.right != null && tmp.right != pnode)
					tmp = tmp.right;
				if(tmp.right == null){ //第一次遍历 == null
					tmp.right = pnode; // 叶子节点的右孩子记录将要遍历的顺序
					pnode = pnode.left;
				} else{ 
					if(prev != null && pnode.val < prev.val){
			     		if(first == null) first = prev; //存第一个反序对的前一个节点 
			     		second = pnode;//存第二个反序对的后一个节点
			     	}
					prev = pnode;
					tmp.right = null; //恢复为空节点
					pnode = pnode.right;
				}
			}
		}
		int temp = second.val;
    	second.val = first.val;
    	first.val = temp;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值