题目描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 64M,其他语言128M
解题思路:最容易想到的就是中序遍历二叉树,用ArrayList存放遍历过程中的所有结点。然后再遍历ArrayList,遍历过程中修改每个结点的指针。
import java.util.ArrayList;
public class Solution {
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree == null){
return null;
}
ArrayList<TreeNode> list = new ArrayList<>();
Convert(pRootOfTree, list);
return Convert(list);
}
//中序遍历,在list中按遍历顺序保存
public static void Convert(TreeNode pRootOfTree, ArrayList<TreeNode> list){
if(pRootOfTree.left != null){
Convert(pRootOfTree.left, list);
}
list.add(pRootOfTree);
if(pRootOfTree.right != null){
Convert(pRootOfTree.right, list);
}
}
//遍历list,修改指针
public static TreeNode Convert(ArrayList<TreeNode> list){
for(int i = 0; i < list.size() - 1; i++){
list.get(i).right = list.get(i + 1);
list.get(i + 1).left = list.get(i);
}
return list.get(0);
}
}
第二种办法是利用二叉树线索化的思想。即在中序遍历的过程中,将节点的左孩子指向后继,右孩子指向前驱。参考二叉线索树的代码,得到的初始代码如下:
public class Solution {
TreeNode pre=null;
public TreeNode Convert(TreeNode pRootOfTree) {
if (pRootOfTree==null)
return null;
Convert(pRootOfTree.left);
if (pre!= null){
pRootOfTree.left=pre;
pre.right=pRootOfTree;
}
pre=pRootOfTree;
Convert(pRootOfTree.right);
return pre;
}
}
但是这样返回得到头指针,指向的是最后一个结点,也就是得到的是一个逆序的双向链表(可以自己根据代码手动算一下,上面的代码,得到的是一个逆序的链表)。需要做一些修改,才能得到正序的链表。
修改的代码如下:
public class Solution {
TreeNode pre=null;
TreeNode root=null;
public TreeNode Convert(TreeNode pRootOfTree) {
if (pRootOfTree==null)
return null;
Convert(pRootOfTree.left);
if (root==null){ //指向链表的第一个节点。
root=pRootOfTree;
}
if (pre!= null){
pRootOfTree.left=pre;
pre.right=pRootOfTree;
}
pre=pRootOfTree;
Convert(pRootOfTree.right);
return root; //返回链表的头指针
}
}
第三种办法,也是最好的办法:反向中序遍历。我们知道,中序遍历都说先左,输出,再右。这样得到的是逆序的链表。那么如果我们中序遍历的时候先右,输出,再左呢?得到是不是正序的链表呢? 答案是肯定的!!! (可以根据代码自己手动算一下,你会发现很神奇!)代码如下(对比一下方法1中的代码):
public class Solution {
TreeNode pre=null;
public TreeNode Convert(TreeNode pRootOfTree) {
if (pRootOfTree==null)
return null;
Convert(pRootOfTree.right); //先遍历右子树
if (pre!= null){ //改变指针方向
pRootOfTree.right=pre;
pre.left=pRootOfTree;
}
pre=pRootOfTree;
Convert(pRootOfTree.left); //再遍历左子树
return pre;
}
}