1.题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
2.思路:
由于要求转换之后的链表是排好序的,我们可以中序遍历树中的每一个结点,这是因为中序遍历算法的特点是按照从小到大的顺序遍历二叉树的每一个结点。
最后,按照中序遍历的顺序,当我们遍历转换到根结点(值为10的结点)时,它的左子树已经转换成一个排序的链表了,并且处在链表中的最后一个结点是当前值最大的结点。我们把值为8的结点和根结点链接起来,此时链表中的最后一个结点就是10了。接着我们去遍历转换右子树,并把根结点和右子树中最小的结点链接起来。
很明显,转换它的左子树和右子树,由于遍历和转换过程是一样的,很自然地想到可以用递归。
3.java实现
递归
public BinaryTreeNode convert(BinaryTreeNode root) {
BinaryTreeNode pre=null;//记录根节点前一个节点,即已转换链表的最后一个元素
pre=convertNode(root,pre);
BinaryTreeNode head=pre;
//System.out.println(head.left.value);
while(head!=null&&head.left!=null) {
head=head.left;
}
return head;
}
public BinaryTreeNode convertNode(BinaryTreeNode pNode,BinaryTreeNode pre) {
if(pNode==null)
return pre;
//遍历左子树
pre=convertNode(pNode.left,pre);
//将当前节点连接到已排序的链表中
pNode.left=pre;
//链表末尾指针指向当前节点
if(pre!=null) {
pre.right=pNode;
}
//更新链表末尾指针为当前指针
pre=pNode;
//System.out.println(pre.value);
//遍历右子树
pre=convertNode(pNode.right,pre);
return pre;
}
非递归:二叉搜索树的中序遍历是一个有序的数组,在中序遍历的时候,用 Pre 指针保存前一个节点,当访问到当前节点的时候,将 Pre 节点右指针,指向当前节点,当前节点的左指针指向 Pre。 这样中序遍历完二叉搜索树,就产生了一个双向链表。
public BinaryTreeNode convertWithStack(BinaryTreeNode root) {
if(root==null)
return null;
BinaryTreeNode cur=root;
BinaryTreeNode pre=null;
Stack<BinaryTreeNode> stack=new Stack<BinaryTreeNode>();
while(!stack.isEmpty()||cur!=null) {
while(cur!=null) {
stack.push(cur);
cur=cur.left;
}
//到达树的最左边,出战
cur=stack.pop();
if(pre==null) {
root=cur;//链表头结点
pre=cur;
}else {
pre.right=cur;
cur.left=pre;
pre=cur;
}
cur=cur.right;
}
return root;
}
用递归实现上面用栈实现的思路:
public class Solution{
BinaryTreeNode pre=null;
BinaryTreeNode head=null;
public BinaryTreeNode convert2(BinaryTreeNode root) {
if(root==null)
return null;
convert2(root.left);
if(pre==null) {
root.left=pre;
head=root;
pre=root;
}else {
pre.right=root;
root.left=pre;
pre=root;
}
convert2(root.right);
return head;
}