[Daily Coding Problem 223] O(1) space in order traversal of a binary tree

本文介绍了一种实现二叉树中序遍历的方法,该方法能够在常数空间复杂度O(1)下完成遍历操作。文章首先提供了一个使用栈实现的传统O(h)空间复杂度的中序遍历算法,并进一步探讨了如何通过修改树结构来避免栈的使用,从而降低空间消耗。

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

Typically, an implementation of in-order traversal of a binary tree has O(h) space complexity, where h is the height of the tree. Write a program to compute the in-order traversal of a binary tree using O(1) space.

 

In-order traversal without recursion with O(h) space, where h is the tree's height.

 

public List<Integer> inOrderTraversal(BinaryTreeNode root) {
    List<Integer> vals = new ArrayList<>();
    if(root == null) {
        return vals;
    }
    Stack<BinaryTreeNode> stack = new Stack<>();
    BinaryTreeNode curr = root;

    while(stack.size() > 0 || curr != null) {
        while(curr != null) {
            stack.push(curr);
            curr = curr.getLeft();
        }
        curr = stack.pop();
        vals.add(curr.getVal());
        curr = curr.getRight();
    }
    return vals;
}

 

O(1) space solution

The reason that the stack solution requires O(h) space consumption is because we must have some way to traverse back to a current node after traversing its left subtree. To avoid this space consumption, we need to restructure the tree while we traverse it, so that going to the right will always go to the "correct" next node. Namely, right after visiting the rightmost node in a left subtree, we continue to visit this rightmost node's right child that will lead us back to the this left subtree's parent. 

 

Take the binary tree below as an example. Starting from root 8, it has a left subtree. Before traversing its left subtree, we need to get the rightmost descendant of this subtree and set its right child to be the root node 8. Otherwise, we wouldn't have any way of coming back to root. So we set 7's right child to be 8. After this step, traverse the left subtree. For node 3, we do the same, setting 1's right child to be 3. Repeat this until a node has no left subtree. At this point, we know we need to add its value to the result list. In an in-order traversal, we visit a node's right child after visiting the node. So we go back to 3. Now here comes a problem. Since we are constrained with constant space, we do not know that 3's left subtree has been traversed. How do we check that this is the case? We apply the same logic here: trying to the rightmost descendant of 3's left child(1) points to 3. After finding out that 1's right child already points to 3, we know that we have already traversed the left subtree with a root node 1. At this point, we need to revert the changes made to node 1 by setting its right child back to null. Then add 3 to the result list and traverse 3's right subtree. 

 

Algorithm:

1. if the current node has no left subtree, visit it;

2. if it has left subtree, make the rightmost descendant node's right child in its left subtree points to itself; 

2(a). If this is already done before, revert the changes, visit the current node, then traverse its right subtree;

2(b). If this has not been done, do the upate, then traverse the current node's left subtree;

3. Repeat steps 1 and 2 until the current node becomes null.

 

This approach uses O(1) space at the cost of slower runtime as we need to traverse each left subtrees of every node twice.

public List<Integer> inOrderTraversalConstantSpace(BinaryTreeNode root) {
    List<Integer> vals = new ArrayList<>();
    BinaryTreeNode curr = root;

    while(curr != null) {
        //add val if there is no left node to go to
        if(curr.getLeft() == null) {
            vals.add(curr.getVal());
            curr = curr.getRight();
        }
        //make the rightmost descendant of curr's left child points to curr
        else {
            BinaryTreeNode rightMostDesc = curr.getLeft();
            while(rightMostDesc.getRight() != null && rightMostDesc.getRight() != curr) {
                rightMostDesc = rightMostDesc.getRight();
            }
            if(rightMostDesc.getRight() == null) {
                rightMostDesc.setRight(curr);
                curr = curr.getLeft();
            }
            else {
                rightMostDesc.setRight(null);
                vals.add(curr.getVal());
                curr = curr.getRight();
            }
        }
    }
    return vals;
}

 

 

 

 

 

This problem basically implements a single threaded binary tree. For more references on this, refer to Threaded Binary Tree: https://www.geeksforgeeks.org/threaded-binary-tree/

 

转载于:https://www.cnblogs.com/lz87/p/11162989.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值