题目描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public TreeNode Convert(TreeNode pRootOfTree) {
}
}
思路分析
二叉搜索树如何与双向链表相关联呢?首先要了解二叉搜索树(BST)的性质,左节点<根节点<右节点
而要满足这个顺序就需要对二叉树进行中序遍历,那么就是已经排好序的链表了
代码
public class Test9 {
public static class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
/**
* 定义:转换后left表示pre,right表示next
* @param pRootOfTree 根结点
* @return
*/
public static TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree==null) return pRootOfTree;
//链表尾节点
TreeNode lastNode=null;
//转换
lastNode=convert(pRootOfTree,lastNode);
//寻找返回的头结点
TreeNode head=lastNode;
while(head.left!=null) {
head = head.left;
}
return head;
}
/**
* 返回当前已转换好的链表的尾结点
* @param root 当前子树的根结点
* @param last 保存当前链表的最后一个指针
* @return 返回当前链表的最后一个结点
*/
public static TreeNode convert(TreeNode root,TreeNode last) {
System.out.println("--------------------------进入convert方法-------------------------------");
if(root==null) return null;
TreeNode p=root;
System.out.println("current root=>"+p.val);
//转换左子树
System.out.println("=========递归左子树=========");
if(root.left!=null) last=convert(root.left,last);
if(last != null){
System.out.println("***************当前根节点***********"+p.val);
System.out.println("当前列表的最后一个节点(当前左子树的最大节点)=>"+last.val);
}else {
System.out.println("***************当前根节点***********"+p.val);
System.out.println("当前列表的最后一个节点(当前左子树的最大节点)=>"+null);
}
//根结点的pre指向左子树的last,左子树的last的next指向根结点
p.left=last;
if(last != null){
System.out.println("***************当前根节点***********"+p.val);
System.out.println("根结点的pre指向左子树的last=>"+last.val);
}else {
System.out.println("***************当前根节点***********"+p.val);
System.out.println("根结点的pre指向左子树的last=>"+null);
}
if(last!=null) last.right=p;
//last指向根结点
last=p;
if(last != null){
System.out.println("***************当前根节点***********"+p.val);
System.out.println("last指向根结点=>"+last.val);
}else {
System.out.println("***************当前根节点***********"+p.val);
System.out.println("last指向根结点=>"+null);
}
//转换右子树
System.out.println("=========递归右子树=========");
if(root.right!=null) last=convert(root.right,last);
return last;
}
public static void main(String[] args){
//构造二叉排序树
TreeNode root=new TreeNode(10);
root.left=new TreeNode(6);
root.right=new TreeNode(14);
root.left.left=new TreeNode(4);
root.left.right=new TreeNode(8);
root.right.left=new TreeNode(12);
root.right.right=new TreeNode(16);
TreeNode head = Convert(root);
}
}
--------------------------进入convert方法-------------------------------
current root=>10
=========递归左子树=========
--------------------------进入convert方法-------------------------------
current root=>6
=========递归左子树=========
--------------------------进入convert方法-------------------------------
current root=>4
=========递归左子树=========
***************当前根节点***********4
当前列表的最后一个节点(当前左子树的最大节点)=>null
***************当前根节点***********4
根结点的pre指向左子树的last=>null
***************当前根节点***********4
last指向根结点=>4
=========递归右子树=========
***************当前根节点***********6
当前列表的最后一个节点(当前左子树的最大节点)=>4
***************当前根节点***********6
根结点的pre指向左子树的last=>4
***************当前根节点***********6
last指向根结点=>6
=========递归右子树=========
--------------------------进入convert方法-------------------------------
current root=>8
=========递归左子树=========
***************当前根节点***********8
当前列表的最后一个节点(当前左子树的最大节点)=>6
***************当前根节点***********8
根结点的pre指向左子树的last=>6
***************当前根节点***********8
last指向根结点=>8
=========递归右子树=========
***************当前根节点***********10
当前列表的最后一个节点(当前左子树的最大节点)=>8
***************当前根节点***********10
根结点的pre指向左子树的last=>8
***************当前根节点***********10
last指向根结点=>10
=========递归右子树=========
--------------------------进入convert方法-------------------------------
current root=>14
=========递归左子树=========
--------------------------进入convert方法-------------------------------
current root=>12
=========递归左子树=========
***************当前根节点***********12
当前列表的最后一个节点(当前左子树的最大节点)=>10
***************当前根节点***********12
根结点的pre指向左子树的last=>10
***************当前根节点***********12
last指向根结点=>12
=========递归右子树=========
***************当前根节点***********14
当前列表的最后一个节点(当前左子树的最大节点)=>12
***************当前根节点***********14
根结点的pre指向左子树的last=>12
***************当前根节点***********14
last指向根结点=>14
=========递归右子树=========
--------------------------进入convert方法-------------------------------
current root=>16
=========递归左子树=========
***************当前根节点***********16
当前列表的最后一个节点(当前左子树的最大节点)=>14
***************当前根节点***********16
根结点的pre指向左子树的last=>14
***************当前根节点***********16
last指向根结点=>16
=========递归右子树=========
简洁代码
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
/**
* 定义:转换后left表示pre,right表示next
* @param pRootOfTree 根结点
* @return
*/
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree==null) return pRootOfTree;
//链表尾节点
TreeNode lastNode=null;
//转换
lastNode=convert(pRootOfTree,lastNode);
//寻找返回的头结点
TreeNode head=lastNode;
while(head.left!=null) {
head = head.left;
}
return head;
}
/**
* 返回当前已转换好的链表的尾结点
* @param root 当前子树的根结点
* @param last 保存当前链表的最后一个指针
* @return 返回当前链表的最后一个结点
*/
public TreeNode convert(TreeNode root,TreeNode last) {
if(root==null) return null;
TreeNode p=root;
//转换左子树
if(root.left!=null) last=convert(root.left,last);
//根结点的pre指向左子树的last,左子树的last的next指向根结点
p.left=last;
if(last!=null) last.right=p;
//last指向根结点
last=p;
//转换右子树
if(root.right!=null) last=convert(root.right,last);
return last;
}
}
总结
本题的关键在于如何处理指针的指向,具体包括如何将当前根节点的前一个节点(p.left)指向左子树的最后一个节点(last)=>p.left = last;如何将左子树的最后一个节点的下一个节点(last.right)指向根节点=>last.right = p
还要注意的是遍历完左子树的时候还需要将当前的根节点加入到链表中,作为新的last=>last = p
然后再遍历右子树
整体的思路还是按照中序遍历的结果:处理左子树=>处理根节点和左子树的最后一个的关系=>处理右子树
参考: