剑指offer第二版——面试题36(java)

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

题目:

输入一颗二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。

要求不能创建任何新的节点,只能调整树中节点指针的指向。

输出转换之后的排序双向链表

参考:

https://www.cnblogs.com/keedor/p/4467040.html

思路:

【方法一】

递归中始终用一个lastNode指向当前已排序的列表的最后位置(详见参考)

 

【方法二】

先定义我们需要让这个函数的输入与输出——

输入:树/子树的根节点

输出:该树/子树转化成双向链表之后的最右节点

规定:每个结点的左节点为更小的数,每个结点的右节点为更大的数

因此,每个树的转化可分为几个大的部分:

1. 将左子树进行转化,得到转化后双向链表的最右节点

2. 将左子树转化后的最右节点,与根节点连接起来,具体为根节点→左 = 最右节点 最右节点→右=根节点

3. 将右子树转化,得到转化后双向链表的最左节点

4. 将右子树转化后的最右节点,往左遍历,直到得到该双向链表的最左节点

5. 将右子树转化后的最左节点,与根节点连接起来,具体为 最左节点→左 = 根节点 根节点→右=最左节点

6. 从根节点往右遍历,直到得到此双向链表中的最右节点,返回该结点

【举例】

以下图为例

1. 对8,先对左子树进行转化得到657的最右节点

    (对657子树进行转化)

    1.1 对6节点,先对其左子树进行转化,得到5的最右节点

        1.1.1 5转化后的链表为5,往右遍历得到最右节点为5——此时双向链表为5,且返回的指针指向最右节点5

    1.2 将6与5进行连接,得到56

    1.3 对6节点的右子树进行转化,得到7的最左节点——7的最左节点是7

        1.3.1 7转化后的链表为7,往左遍历得到最左节点为7——此时双向链表为7,且返回的指针指向最左节点7

    1.4 6节点与7相连,得到567,且指针指向的中间6

    1.5 往右遍历,得到最右节点7——此时双向链表为567,且返回的指针指向最右节点7

2. 返回的节点7与8相连,得到5678

3. 对右子树进行转化得到10911的最左节点

    (对10911子树进行转化)

    3.1 对10,先对其左子树进行转化,得到9的最右节点(9)

    3.2 10与9的最右节点相连,得到910

    3.3 对10,转化其右子树,得到11的最左节点(11)

    3.4 10与11相连,得到91011,且指针指向中间的10

    3.5 往左遍历,得到最左节点9——此时双向链表为91011,且返回的指针指向最左节点9

4. 返回的节点9与8相连,得到567891011

结束

    

// 方法一
// 2019-05-10
public class Q36 {
	public static void main(String[] args) {
		BinaryTreeNode head = getTree();
		BinaryTreeNode h = tr(head);
		while(h!=null) {
			System.out.printf("%d ", h.val);
			h = h.right;
		}
	}
	
	public static BinaryTreeNode tr(BinaryTreeNode head) {
		BinaryTreeNode lastNode = null;
		lastNode = transfor(head, lastNode);
		while(lastNode.left!=null) {
			lastNode = lastNode.left;
		}
		return lastNode;
	}

	public static BinaryTreeNode transfor(BinaryTreeNode root,BinaryTreeNode lastNode) {
		if(root==null) {
			return lastNode;
		}
		
		BinaryTreeNode current = root;
		if(current.left!=null) {
			lastNode = transfor(current.left, lastNode);
		}
		
		current.left = lastNode;
		
		if(lastNode!=null) {
			lastNode.right = current;
		}
		
		lastNode = current;
		
		if(current.right!=null) {
			lastNode = transfor(current.right, lastNode);
		}
	
		return lastNode;
	}

	public static BinaryTreeNode getTree() {
		BinaryTreeNode node10 = new BinaryTreeNode(10);
		BinaryTreeNode node6 = new BinaryTreeNode(6);
		BinaryTreeNode node4 = new BinaryTreeNode(4);
		BinaryTreeNode node8 = new BinaryTreeNode(8);
		BinaryTreeNode node12 = new BinaryTreeNode(12);
		BinaryTreeNode node16 = new BinaryTreeNode(16);
		BinaryTreeNode node14 = new BinaryTreeNode(14);
		
		node10.left = node6;
		node10.right = node14;
		node6.left = node4;
		node6.right = node8;
		node14.left = node12;
		node14.right = node16;
		
		return node10;
	}
}
// 方法二
// 2019-06-25
public static BinaryTreeNode transfor(BinaryTreeNode root) {
    if(root.left==null && root.right == null) {
        return root;
    }
		
    // 有左子树
    if(root.left!=null) {
        BinaryTreeNode left = transfor(root.left);
        root.left = left;
        left.right = root;
    }
		
    // 有右子树
    if(root.right!=null) {
        BinaryTreeNode right = transfor(root.right);
        while(right!=null && right.left!=null) {
            right = right.left;
        }
            root.right = right;
            right.left = root;
        }
		
        while(root!=null && root.right!=null) {
            root = root.right;
        }
        return root;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值