首页 > 试题广场 >

二叉搜索树与双向链表

[编程题]二叉搜索树与双向链表
  • 热度指数:626299 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。如下图所示


数据范围:输入二叉树的节点数 ,二叉树中每个节点的值
要求:空间复杂度(即在原树上操作),时间复杂度

注意:
1.要求不能创建任何新的结点,只能调整树中结点指针的指向。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继
2.返回链表中的第一个节点的指针
3.函数返回的TreeNode,有左右指针,其实可以看成一个双向链表的数据结构
4.你不用输出双向链表,程序会根据你的返回值自动打印输出

输入描述:
二叉树的根节点


输出描述:
双向链表的其中一个头节点。
示例1

输入

{10,6,14,4,8,12,16}

输出

From left to right are:4,6,8,10,12,14,16;From right to left are:16,14,12,10,8,6,4;

说明

输入题面图中二叉树,输出的时候将双向链表的头节点返回即可。     
示例2

输入

{5,4,#,3,#,2,#,1}

输出

From left to right are:1,2,3,4,5;From right to left are:5,4,3,2,1;

说明

                    5
                  /
                4
              /
            3
          /
        2
      /
    1
树的形状如上图       

说明:本题目包含复杂数据结构TreeNode,点此查看相关信息
推荐
方法一:非递归版
解题思路:
1.核心是中序遍历的非递归算法。
2.修改当前遍历节点与前一遍历节点的指针指向。
    import java.util.Stack;
    public TreeNode ConvertBSTToBiList(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()){
    		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.将左子树构造成双链表,并返回链表头节点。
2.定位至左子树双链表最后一个节点。
3.如果左子树链表不为空的话,将当前root追加到左子树链表。
4.将右子树构造成双链表,并返回链表头节点。
5.如果右子树链表不为空的话,将该链表追加到root节点之后。
6.根据左子树链表是否为空确定返回的节点。
    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点中的定位作了修改,新增一个全局变量记录左子树的最后一个节点。
    // 记录子树链表的最后一个节点,终结点只可能为只含左子树的非叶节点与叶节点
    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;        
    }

编辑于 2015-08-18 23:36:07 回复(111)
TreeNode pre=new TreeNode(0) ,p1=pre;
public TreeNode Convert(TreeNode pRootOfTree) {
    if(pRootOfTree==null){
        return null;
    }
    dfs(pRootOfTree);
    pre.right.left=null; // 避免把pre节点算进去
    return pre.right;
}

public void dfs(TreeNode pRoot){
    if(pRoot==null){
        return;
    }
    dfs(pRoot.left);
    // 中序遍历,依次进行节点连接,p1向右传递
    pRoot.left=p1;
    p1.right=pRoot;
    p1=p1.right;
    dfs(pRoot.right);
}

编辑于 2024-03-17 14:10:33 回复(0)
public class Solution {

    private TreeNode pre = null;

    public TreeNode Convert(TreeNode pRootOfTree) {
        if (null == pRootOfTree) {
            return null;
        }
        inorder(pRootOfTree);
        TreeNode head = pRootOfTree;
        while (head.left != null) {
            head = head.left;
        }
        return head;
    }

    private void  inorder(TreeNode root) {
        if (null == root) {
            return ;
        }
        inorder(root.left);
        if (pre != null) {
            pre.right = root;
            root.left = pre;
        }
        pre = root;
        inorder(root.right);
    }

}

发表于 2023-10-13 17:21:41 回复(0)
import java.util.*;

public class Solution {
    // 中序遍历可以输出二叉搜索树的顺序
    // 只需要将输出变成构建一条新的二叉树(双向链表)即可
    public TreeNode Convert(TreeNode pRootOfTree) {
        if (pRootOfTree == null) {
            return null;
        }
        Stack<TreeNode> stack = new Stack<>();
        boolean isFirst = true;
        // head是返回的头节点,temp是用于与新节点链接的指针
        TreeNode head = new TreeNode(0);
        TreeNode temp = head;
        while (pRootOfTree != null || !stack.isEmpty()) {
            while (pRootOfTree != null) {
                stack.push(pRootOfTree);
                pRootOfTree = pRootOfTree.left;
            }
            TreeNode peek = stack.peek();
            pRootOfTree = stack.pop();
            // 原本该是输出,现在变成构建二叉树
            if (isFirst) {
                head = peek;
                temp = peek;
                isFirst = false;
            } else {
                temp.right = peek;
                peek.left = temp;
                temp = temp.right;
            }
            pRootOfTree = pRootOfTree.right;

        }
        return head;
    }
}

发表于 2023-08-15 10:38:52 回复(0)
import java.util.*;
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    TreeNode res = null;
    TreeNode pre = null;
    public TreeNode Convert(TreeNode pRootOfTree) {
        midOrder(pRootOfTree);
        return res;
    }
    public void midOrder(TreeNode root) {
        if(root != null) {
            midOrder(root.left);
            if(res == null) {
                res = root;
                pre = root;
            } else {
                pre.right = root;
                root.left = pre;
                pre = root;
            }
            midOrder(root.right);
        }
    }
}
发表于 2023-08-07 11:02:00 回复(0)
import java.util.*;
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    TreeNode pre = null;
    public TreeNode Convert(TreeNode pRootOfTree) {
        if (pRootOfTree == null) return null;
        InOrder(pRootOfTree);
        TreeNode p = pRootOfTree;
        while (p.left != null) {
            p = p.left;
        }
        return p;
    }
    public void InOrder(TreeNode Root) {
        if (Root == null) {
            return;
        }
        InOrder(Root.left);
        Root.left = pre;
        if (pre != null) {
            pre.right = Root;
        }
        pre = Root;
        InOrder(Root.right);
    }
}

发表于 2023-07-24 20:24:00 回复(0)
import java.util.*;
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {

    public TreeNode prev = null;

    public void convertChild(TreeNode pCur) {
        if(pCur == null) {
            return;
        }
        convertChild(pCur.left);

        pCur.left = prev;
        if(prev != null) {
            prev.right = pCur;
        }
        prev = pCur;
        convertChild(pCur.right);

    }

    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree == null) {
            return null;
        }
        convertChild(pRootOfTree);
        TreeNode head = pRootOfTree;

        while(head.left != null) {
            head = head.left;
        }
        return head;
    }
}
发表于 2023-07-16 17:13:18 回复(0)
public class Solution {
    TreeNode head=null;//赋初值为null
    TreeNode pre=null;
    //双向链表必然要定义head、pre
    public TreeNode Convert(TreeNode pRootOfTree) {
        build(pRootOfTree);
        return head;
    }
    public void build(TreeNode root){
        //必然是中序遍历
        if(root==null) return ;
        build(root.left);
        if(pre==null){
            pre=root;
            head=root;
        }else{
            pre.right=root;//这里head、pre定义为TreeNode  所以这里是pre.right  head.left
            root.left=pre;//root来回倒
            pre=root;
        }
        build(root.right);

    }

发表于 2023-07-13 22:21:11 回复(0)
import java.util.*;
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }
}
*/

public class Solution {
    public TreeNode pre=null;
    public TreeNode head=null;
    public TreeNode Convert(TreeNode root) {
        //如果根节点为空则为空
        if(root==null){
            return null;
        }
        //用来保存创建的双向链表
        ArrayList<TreeNode> tree=new ArrayList<>();
        //中序遍历
        mid(root,tree);
        //清空tree节点每个左右分支
        for(int i=0;i<tree.size();i++){
            TreeNode tmp=tree.get(i);
            tmp.left=null;
            tmp.right=null;
        }
        //开始构建从左到右单向链表
        for(int i=0;i<tree.size()-1;i++){
            TreeNode tmp=tree.get(i);
            tmp.right=tree.get(i+1);
        }
        //开始构建从右到左的单向链表
        for(int i=tree.size()-1;i>0;i--){
            TreeNode tmp=tree.get(i);
            tmp.left=tree.get(i-1);
        }
        //返回第一个tree节点,就是双向链表的头节点
        return tree.get(0);
    }
    public void mid(TreeNode root,ArrayList<TreeNode> tree){
        if(root==null){
            return;
        }
        mid(root.left,tree);
        tree.add(root);
        mid(root.right,tree);
    }
}

发表于 2023-05-09 08:48:46 回复(0)
这叫排好序?

发表于 2023-04-24 16:58:08 回复(0)
递归直接建立链表
    public TreeNode hair = new TreeNode(-1);
    public TreeNode temp = hair;
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree == null){
            return null;
        }
        convertSub(pRootOfTree);
        hair.right.left = null;
        return hair.right;
    }

    public void convertSub(TreeNode pRootOfTree) {
        if(pRootOfTree == null){
            return;
        }
        convertSub(pRootOfTree.left);
        temp.right = pRootOfTree;
        pRootOfTree.left = temp;
        temp = pRootOfTree;
        convertSub(pRootOfTree.right);
    }


发表于 2023-03-23 21:18:53 回复(0)
整了一种奇奇怪怪的写法,AC和自测都没啥问题
public class Solution {
    boolean isLeaf(TreeNode root){
        if(root==null)return false;
        if(root.left==null&&root.right==null)return true;
        return false;
    }
    TreeNode doi(TreeNode root, int flag){
        System.out.println("root:"+root.val+"flag:"+flag);
        if(flag==0&&isLeaf(root.left)){
            root.left.right=root;
            return root.left;
        }
        if(flag==1&&isLeaf(root.right)){
            root.right.left=root;
            return root.right;
        }
        if(flag==0&&root.left==null)return root;
        else if(flag==0&&root.left!=null){
            TreeNode left=root.left;
            TreeNode res=doi(left,0);
            TreeNode pre=doi(left,1);
            root.left=pre;pre.right=root;
            return res;
        }
        if(flag==1&&root.right==null)return root;
        else if(flag==1&&root.right!=null){
            TreeNode right=root.right;
            TreeNode bac=doi(right,0);
            TreeNode res=doi(right,1);            
            root.right=bac;bac.left=root;
            return res;
        }
        return null;
    }
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree==null)return null;
        if(isLeaf(pRootOfTree))return pRootOfTree;
        TreeNode res=doi(pRootOfTree,0);
        doi(pRootOfTree,1);
        return res;
    }
}


发表于 2023-02-28 18:50:55 回复(0)
非递归,非栈或堆:
递归方程本身占空间所以O(N),栈或堆就算没有新创造节点指针也占空间。
思路是:通过旋转把树变成一条棍子(这时候还是单链表),再连成双链表。
while (节点!=null) {
    while (节点左边!=null){ // 还要继续旋转
        左旋节点...
    }
    节点 = 节点->右节点;
}
然后再把单链表连成双链表就行了。
public class Solution {
public TreeNode Convert(TreeNode pRootOfTree) {
    if (pRootOfTree == null) {
        return null;
    }
    //找到最小头
    TreeNode head = pRootOfTree;
    while (head.left != null) {
        head = head.left;
    }

    // 旋转直到树变成一条
    TreeNode curr = pRootOfTree;
    TreeNode pre = null;
    TreeNode tmp = null;

    while (curr != null) {
        while (curr.left != null) {
            tmp = curr.left;
            curr.left = tmp.right;
            tmp.right = curr;
            curr = tmp;
        }
        if (pre != null) {
            pre.right = curr;
        }
        pre = curr;
        curr = curr.right;

    }
    // 把单链表连城双链表
    pre = head;
    curr = pre.right;
    while (curr != null) {
        curr.left = pre;
        pre = curr;
        curr = curr.right;
    }
    return head;
}
}

发表于 2023-02-20 22:02:00 回复(2)
1. 中序遍历,升序存入数组
2. 根据数组重建双向链表

public class Solution {
    public TreeNode Convert(TreeNode pRootOfTree) {
        List<TreeNode> list = new ArrayList<>();
        traveMid(pRootOfTree, list);
        // 根据数组重建双向链表
        for (int i=0; i<list.size()-1; i++) {
            TreeNode p = (TreeNode)list.get(i);
            TreeNode q = (TreeNode)list.get(i+1);

            p.right = q;
            q.left = p;
        }
        return list.isEmpty() ? null : (TreeNode)list.get(0);
    }

    private void traveMid(TreeNode node, List<TreeNode> list) {
        if (node == null) {
            return;
        }
        traveMid(node.left, list);
        list.add(node);
        traveMid(node.right, list);
    }
}


发表于 2023-02-09 19:05:29 回复(0)
import java.util.*;
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {

    private TreeNode prev;
    private TreeNode head;
    private TreeNode leftLast;

    public TreeNode Convert(TreeNode root) {
        if (root == null) {
            return null;
        }
       // doConvert(root);
       // return head;
       return convert3(root);
    }
    //方法3 非递归-栈
    private TreeNode convert3(TreeNode root) {
     Stack<TreeNode> stack = new Stack<>();
     TreeNode p = root;
     boolean isFirst = true;
     TreeNode prev = null;
     while(p != null || !stack.isEmpty()) {
         while(p != null) {
             stack.push(p);
             p = p.left;
         }
         p = stack.pop();
         if (isFirst) {
             root = p;
             prev = p;
             isFirst = false;
         }else {
             prev.right = p;
             p.left = prev;
             prev = p;
         }

         p = p.right;
     }
     return root;


    }
 

    //方法2
    private TreeNode convert2(TreeNode root) {
        if (root == null) {
            return null;
        }
        if (root.left == null && root.right == null) {
            leftLast = root;
            return root;
        }
       TreeNode left = convert2(root.left);
       if (left != null) {
           leftLast.right = root;
           root.right = leftLast;
       }
       TreeNode right = convert2(root.right);
       if (right != null) {
           right.left = root;
           root.right = right;
       }
       return left != null ? left : right;
    }
 



    //方法1--递归
    private void doConvert(TreeNode root) {
        if (root == null) {
            return;
        }
        doConvert(root.left);
        if (prev == null) {
            prev = root;
            head = root;
        } else {
            root.left = prev;
            prev.right = root;
            prev = root;
        }
         doConvert(root.right);
    }
}

发表于 2022-11-06 16:22:02 回复(0)
public class Solution {

    TreeNode prev = null;
    public void inorder(TreeNode root){
        if(root == nullreturn;
        inorder(root.left);
        root.left = prev;
        if(prev != null){
        prev.right = root;
        }
        prev = root;
        //System.out.print(root.val+" ");
        inorder(root.right);
    }

    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree == nullreturn null;
        inorder(pRootOfTree);
        TreeNode head = pRootOfTree;
        while(head.left != null){
            head = head.left;
        }
        return head;
    }
}
发表于 2022-10-09 16:23:54 回复(0)
import java.util.*;
/**
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;
        List<TreeNode> t = new ArrayList();
        bfs(root,t);
        TreeNode pre = null;
        for(int i=0,max = t.size()-1;i<max;i++){
            t.get(i).left = pre;
            t.get(i).right = t.get(i+1);
            pre = t.get(i);
        }
        t.get(t.size()-1).left = pre;
        return t.get(0);
    }
    
    
    public void bfs(TreeNode root,List list){
        if(null!=root){
            if(null!=root.left)bfs(root.left,list);
            list.add(root);
            if(null!=root.right)bfs(root.right,list);
        }
    }
}

发表于 2022-09-06 16:16:24 回复(0)
import java.util.*;
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    ArrayList<TreeNode> l = new ArrayList<>();
    
    void sort(TreeNode root){
        if(root==null) return;
        if(root.left!=null){
            sort(root.left);
        }
        l.add(root);
        if(root.right!=null){
            sort(root.right);
        }
    }
    
    
    public TreeNode Convert(TreeNode pRootOfTree) {
        TreeNode head = null;
        if(pRootOfTree == null){
            return head;
        }
        sort(pRootOfTree);
        head = l.get(0);
        for(int i = 0 ; i < l.size()-1;i++){
            l.get(i).right = l.get(i+1);
        }
        for(int i = l.size()-1 ; i >0 ;i--){
            l.get(i).left = l.get(i-1);
        }
        head.left = null;
        l.get(l.size()-1).right =null;
        return head;
    }
}
发表于 2022-09-01 11:25:50 回复(0)