题目描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
思路:
递归:边界条件判断,然后递归左边,返回的是首节点地址,找到左子树最右边节点;若左子树非空,则左子树构成的双链表添加root节点;递归右边,若右子树非空则在root节点后面添加右子树的双链表
非递归:
1
.核心是中序遍历的非递归算法。
2
.修改当前遍历节点与前一遍历节点的指针指向。
C/C++:运行时间:4ms 占用内存:480k
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
TreeNode* Convert(TreeNode* root)
{
if(root==NULL) return NULL;//递归边界
if(root->left==NULL && root->right==NULL) return root;//递归边界
TreeNode* left = Convert(root->left);//递归左边
TreeNode* p = left;
while(p!=NULL && p->right!=NULL)//找左子树最右节点
p = p->right;//当p->right为NULL的时候跳出循环
if(left)//若左子树不空
{
p->right = root;
root->left = p;
}
TreeNode* right = Convert(root->right);//递归右边
if(right)//若右子树不空
{
root->right = right;
right->left = root;
}
return left ? left : root;
}
};
Java:运行时间:18ms 占用内存:9464k
/**
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)//如果left不为空,说明左子树非空
{
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;
}
Python:
运行时间:35ms
占用内存:5736k
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
leftlast = None
def Convert(self, root):
if not root: return None
if not root.left and not root.right:#root节点左右孩子均为None
self.leftlast = root
return root
left = self.Convert(root.left)#递归左边
if left:#如果left不为None
self.leftlast.right = root
root.left = self.leftlast
self.leftlast = root
right = self.Convert(root.right)#递归右边
if right:
right.left = root
root.right = right
if left:return left
else: return root
#return left if left else root
非递归Java: 运行时间:19ms 占用内存:9496k
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
import java.util.Stack;
public class Solution
{
//方法一:非递归版
//1.核心是中序遍历的非递归算法。
//2.修改当前遍历节点与前一遍历节点的指针指向。
public TreeNode Convert(TreeNode root)
{
if(root==null)
return null;
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode p = root;
TreeNode pre = null;// 用于保存中序遍历序列的上一节点
boolean isFirst = true;
while(p!=null || !stack.isEmpty())//p非空或者stack非空
{
while(p!=null)
{
stack.push(p);
p = p.left;
}
p = stack.pop();
if(isFirst)
{
root = p;// 将中序遍历序列中的第一个节点记为root
pre = root;
isFirst = false;
}else{
pre.right = p;
p.left = pre;
pre = p;
}
p = p.right;
}
return root;
}
}