剑指Offer - 二叉搜索树与双向链表 (C/C++, Java, Python)

题目描述

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

思路:

        递归:边界条件判断,然后递归左边,返回的是首节点地址,找到左子树最右边节点;若左子树非空,则左子树构成的双链表添加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;
    }
}




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值