算法——二叉树转链表转换问题

前序遍历转换问题

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
leetcode

迭代

解题思路:通过栈来中序遍历这个二叉搜索树。

  • 遍历的时候,第一次遍历到底部的时候,那个节点就是头节点。
  • 每次遍历的时候都要存下当前节点为前节点。在之后的遍历中,用前节点的right指向下一个节点节点。在用当前节点left指向前一个节点。
  • 如果这里的right和left发生对换也可以,不过迭代之后的顺序就要发生改变,因为我们每次都是去判断其右子树是否存在,如果前面就用right去指向前一个节点的话,不就进入一个循环了。
  • 最后需要把尾节点和头节点连上。
class Solution {
    public Node treeToDoublyList(Node root) {
        Deque<Node> stack = new LinkedList<>();
        Node pre = null, head = null;

        if(root == null) return root;

        while(root != null || !stack.isEmpty()) {
            while(root != null) {
                stack.push(root);
                root = root.left;
            }

            root = stack.pop();
            if(pre == null) {
                head = root;
            } else {
                pre.right = root;
                root.left = pre;
            }

            pre = root;

            root = root.right;
        }
        
        pre.right = head;
        head.left = pre;

        return pre;
    }
}

递归做法

其实二者的连接思路相同。

class Solution {
    // 1. 中序,递归
    Node pre, head;
    public Node treeToDoublyList(Node root) {
        // 边界值
        if(root == null) return null;
        dfs(root);

        // 题目要求头尾连接
        head.left = pre;
        pre.right = head;
        // 返回头节点
        return head;
    }
    void dfs(Node cur) {
        // 递归结束条件
        if(cur == null) return;
        dfs(cur.left);
        // 如果pre为空,就说明是第一个节点,头结点,然后用head保存头结点,用于之后的返回
        if (pre == null) head = cur;
        // 如果不为空,那就说明是中间的节点。并且pre保存的是上一个节点,
        // 让上一个节点的右指针指向当前节点
        else if (pre != null) pre.right = cur;
        // 再让当前节点的左指针指向父节点,也就连成了双向链表
        cur.left = pre;
        // 保存当前节点,用于下层递归创建
        pre = cur;
        dfs(cur.right);
    }
}

后序遍历转换问题

给定一个二叉树,原地将它展开为一个单链表。
leetcode

例如,给定二叉树

    1
   / \
  2   5
 / \   \
3   4   6
将其展开为:

1
 \
  2
   \
    3
     \
      4
       \
        5
         \
          6

递归

利用迭代的后续遍历。

class Solution {
    TreeNode last = null;
    public void flatten(TreeNode root) {
        if(root == null) return ;
        flatten(root.right);
        flatten(root.left);
        root.right = last;
        root.left = null;
        last = root;

    }
}

迭代

利用辅助栈后序遍历二叉树,然后依次保存前一节点,然后将当前节点的左右子树指向正确位置即可。


class Solution {

    public void flatten(TreeNode root) {
        if(root == null) return;
    
        Deque<TreeNode> stack = new LinkedList<>();
        TreeNode last = null, pre = null;

        while(root != null || !stack.isEmpty()) {
            while(root != null) {
                stack.push(root);
                root = root.right;
            }

            root = stack.peek();

            if(root.left != null && root.left != last) {
                root = root.left;
            } else {
                stack.pop();
                root.left = null;
                root.right = last;
                last = root;
                root = null;
            }
            
        }
    }
}
posted @ 2020-11-23 15:47  lippon  阅读(261)  评论(0编辑  收藏  举报