分析:根据二叉搜索树:左 < 根 < 右的特点,应该采用中序遍历的方式访问这棵二叉树,自然有递归和非递归两种方式实现。因为二叉树中的结点包含
数据域和左右指针域,而双向链表的结点包含数据域和指向前驱和后继的两个指针域,因此不需要创建任何新的结点,只需要在二叉树的基础上修改指针域即可。
将二叉树的遍历应用到解决问题的过程中。
1、递归实现
(1)递归调用函数将当前根结点的左子树转换成双向链表,返回最左边的结点;
(2)定位到左子树对应双向链表的最后一个结点;
(3)如果左子树不为空,那么将当前根结点加入到双向链表(最后一个);
(4)递归调用函数将当前根结点的右子树转换成双向链表,返回最左边的结点;
(5)将右子树对应的链表加入到整个链表中。
/**
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 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、非递归实现(借助栈实现二叉树的中序遍历,在遍历的过程中将visit操作具体化为修改结点的指针域)
import
java.util.Stack;
/**
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) {
if
(pRootOfTree ==
null
)
return
null
;
TreeNode p = pRootOfTree, pre =
null
; // 在链表中加入一个新的结点,总要知道它的前驱结点
Stack<TreeNode> s =
new
Stack<>();
boolean
isFirst =
true
; // 判断是否是第一个结点
do
{
while
(p !=
null
) {
s.push(p);
p = p.left;
}
p = s.pop();
if
(isFirst) { // 如果是则将前驱指向它,并更改标记
pre = p;
isFirst =
false
;
}
else
{
pre.right = p;
p.left = pre;
pre = p;
}
p = p.right;
}
while
(p !=
null
|| !s.isEmpty());
while
(pre.left !=
null
)
pre = pre.left;
return
pre;
}
}
|