剑指offer 26.分解让复杂问题简单 二叉搜索树与双向链表

题目描述

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
 
解题思路:
1.核心是中序遍历的非递归算法。
2.修改当前遍历节点与前一遍历节点的指针指向。

 

package jianzhioffer.tree;

import java.util.Stack;

import jianzhioffer.tree.Convert.TreeNode;

/**
 * 
 * @author Transkai
 *
 */
public class Convert {
    
  public TreeNode Convert(TreeNode pRootOfTree) {
    if (pRootOfTree==null) {
        return null;
    }
    Stack<TreeNode> stack=new Stack<TreeNode>();
    TreeNode p=pRootOfTree;
    TreeNode pre=null;//用于保存中序遍历的上一个节点
    boolean isFirst=true;
    while(p!=null||!stack.isEmpty()){
    while(p!=null) {
        stack.add(p);
        p=p.left;        
    }
    p=stack.pop();
    if (isFirst) {    
        pRootOfTree=p;// 将中序遍历序列中的第一个节点记为root
        pre=pRootOfTree;
        isFirst=false;
    }
    else {
        pre.right=p;
        p.left=pre;
        pre=p;
    }
      p=p.right;
     }
      return pRootOfTree;        
    }
  public static void main(String[] args) {
        TreeNode treeNode=new TreeNode(6);
        TreeNode treeNode2=new TreeNode(4);
        TreeNode treeNode3=new TreeNode(8);
        TreeNode treeNode4=new TreeNode(3);
        TreeNode treeNode5=new TreeNode(5);
        TreeNode treeNode6=new TreeNode(7);
        TreeNode treeNode7=new TreeNode(9);
        treeNode.left=treeNode2;
        treeNode.right=treeNode3;
        treeNode2.left=treeNode4;
        treeNode2.right=treeNode5;
        treeNode3.left=treeNode6;
        treeNode3.right=treeNode7;
        Convert convert=new Convert();
        TreeNode tNode=convert.Convert(treeNode);
        while(tNode!=null) {
            System.out.println(tNode.val);
            tNode=tNode.right;
        }
    }    
    
    
    
    
static class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }    
 }

}

 

 

方法二:递归版
解题思路:
1.将左子树构造成双链表,并返回链表头节点。
2.定位至左子树双链表最后一个节点。
3.如果左子树链表不为空的话,将当前root追加到左子树链表。
4.将右子树构造成双链表,并返回链表头节点。
5.如果右子树链表不为空的话,将该链表追加到root节点之后。
6.根据左子树链表是否为空确定返回的节点。
    
public TreeNode Convert(TreeNode root) {
        if(root==null)
            return null;
        if(root.left==null&&root.right==null)
            return root;
        // 1.将左子树构造成双链表,并返回链表头节点
        TreeNode left = Convert(root.left);
        TreeNode p = left;
        // 2.定位至左子树双链表最后一个节点
        while(p!=null&&p.right!=null){
            p = p.right;
        }
        // 3.如果左子树链表不为空的话,将当前root追加到左子树链表
        if(left!=null){
            p.right = root;
            root.left = p;
        }
        // 4.将右子树构造成双链表,并返回链表头节点
        TreeNode right = Convert(root.right);
        // 5.如果右子树链表不为空的话,将该链表追加到root节点之后
        if(right!=null){
            right.left = root;
            root.right = right;
        }
        return left!=null?left:root;       
    }

 

方法三:改进递归版
解题思路:
思路与方法二中的递归版一致,仅对第2点中的定位作了修改,新增一个全局变量记录左子树的最后一个节点。
    
// 记录子树链表的最后一个节点,终结点只可能为只含左子树的非叶节点与叶节点
    protected TreeNode leftLast = null;
    public TreeNode Convert(TreeNode root) {
        if(root==null)
            return null;
        if(root.left==null&&root.right==null){
            leftLast = root;// 最后的一个节点可能为最右侧的叶节点
            return root;
        }
        // 1.将左子树构造成双链表,并返回链表头节点
        TreeNode left = Convert(root.left);
        // 3.如果左子树链表不为空的话,将当前root追加到左子树链表
        if(left!=null){
            leftLast.right = root;
            root.left = leftLast;
        }
        leftLast = root;// 当根节点只含左子树时,则该根节点为最后一个节点
        // 4.将右子树构造成双链表,并返回链表头节点
        TreeNode right = Convert(root.right);
        // 5.如果右子树链表不为空的话,将该链表追加到root节点之后
        if(right!=null){
            right.left = root;
            root.right = right;
        }
        return left!=null?left:root;       
    }

 

posted @ 2019-07-26 10:57  Transkai  阅读(156)  评论(0编辑  收藏  举报