【剑指offer】36. 二叉搜索树与双向链表

97 阅读2分钟

题目描述

在这里插入图片描述

在这里插入图片描述

// 36. 二叉搜索树与双向链表


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

// 我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一
// 个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点
// ,最后一个节点的后继是第一个节点。

// 特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左
// 指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一
// 个节点的指针。



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

题解

// 二叉搜索树(BST)的中序遍历可以按照升序取元素,
// 因此通过中序遍历构建双向指针,最后再打通循环即可(力扣)。
// 力扣
// 注意力扣这里需要双向循环链表,所以比牛客要稍微难一丢丢
// 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
// 内存消耗:37.6 MB, 在所有 Java 提交中击败了89.23%的用户
class Solution {
	private Node pre = null;
	private Node head = null;

    public Node treeToDoublyList(Node root) {
        if (root == null)
			return null;
		// 开始中序遍历,以升序遍历BST结点。
		inOrder(root);
		// 遍历完,pre在链表尾结点,把头尾结点搭建双向指针
		pre.right = head;
		head.left = pre;
		return head;  // 返回链表头指针
    }
	
	// 中序遍历函数
	private void inOrder(Node node) {
		if (node == null)
			return;
		inOrder(node.left);
		// 在两个中序遍历函数之间,即为当前结点遍历位置。
		// 如果pre为空,说明node是链表头结点
		// 如果pre非空,说明中序遍历已经过了头结点,node遍历到了下一个结点
		// 而此时pre还在上一个结点位置(头结点),这就可以在pre和node之间搭建双向指针
		if (pre != null) {
			node.left = pre;  // node上一结点指向pre
			pre.right = node;  // pre下一结点指向node
		}
		else  // pre为空,说明node是链表头结点,令head指向链表头结点
			head = node;
		pre = node;  // pre移动至node(移动至下一个遍历节点)
		inOrder(node.right);
	}
}


// 牛客
// 牛客需要稍微修改一下,牛客这里只需要双向链表,没说要双向循环链表
// 运行时间:10ms
// 占用内存:9876k
public class Solution {
    private TreeNode pre = null;
    private TreeNode head = null;
    
    public TreeNode Convert(TreeNode pRootOfTree) {
        if (pRootOfTree == null)
			return null;
		// 开始中序遍历,以升序遍历BST结点。
		inOrder(pRootOfTree);
		return head;  // 返回链表头指针
    }
    
    private void inOrder(TreeNode node) {
		if (node == null)
			return;
		inOrder(node.left);
		if (pre != null) {
			node.left = pre;
			pre.right = node;  
		}
		else  
			head = node;
		pre = node; 
		inOrder(node.right);
    }
}