剑指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; }