剑指Offer对答如流系列

面试题36:二叉搜索树与双向链表

题目描述

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

二叉树节点的定义如下:

    public class Node {
        int val = 0;
        Node left = null;
        Node right = null;

        public Node(int val) {
            this.val = val;
        }
    }

比如,输入下图的二叉搜索树,则输出转换之后的排序双向链表。
在这里插入图片描述

在这里插入图片描述

问题分析

二叉搜索树中序遍历的结果是排序的。

问题的解答一下子就明朗了,中序遍历先处理左子树,再处理根结点,之后处理右子树。在处理时,我们构建双向链表。

整个思路的大致流程:假设左子树处理完了,就要处理根结点,而根结点必须知道左子树的最大结点,所以要用函数返回值记录下来;之后处理右子树,右子树的最小结点(也用中序遍历得到)要和根结点链接。

在这里插入图片描述
在这里插入图片描述

问题解答

(1)递归写法

    public Node Convert(Node root) {
        
        if (root == null) {
            return root;
        }
        
        // 处理左子树,获得左子树链表的头结点
        Node left = Convert(root.left);
        Node p = left;
        if (left != null) {
            // 找到左子树链表的末尾结点
            while (p.right != null) {
                p = p.right;
            }
            // 连接结点 
            p.right = root;
            root.left = p;
        }
        // 处理右子树,获得右子树链表的头结点
        Node right = Convert(root.right);
        // 连接结点
        if (right != null) {
            root.right = right;
            right.left = root;
        }
        return left == null ? root : left;
    }

(2)非递归写法

利用非递归中序遍历来连接结点

 public Node Convert(Node root) {
        Node head = null;
        Node pre = null;
        LinkedList<Node> stack = new LinkedList<>();
        while (root != null || !stack.isEmpty()) {
            // 把root当作引用使用
            while (root != null) {
                stack.push(root);
                root = root.left;
            }
            Node node = stack.pop();
            if (head == null) {
                head = node;
                pre = node;
            } else {
                node.left = pre;
                pre.right = node;
                pre = node; // 别漏写了
            }
            root = node.right;
        }
        return head;
    }
原文地址:https://www.cnblogs.com/JefferyChenXiao/p/12246414.html