二叉搜索树改为双向链表

题目描述

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

时间限制: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;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值