二叉树与链表

一、二叉树转链表

思路一:递归版本

思路是先利用DFS的思路找到最左子节点,然后回到其父节点,把其父节点和右子节点断开,将原左子结点连上父节点的右子节点上,然后再把原右子节点连到新右子节点的右子节点上,然后再回到上一父节点做相同操作。步骤如下:

首先找到最左节点3

     1
    / \
   2   5
  / \    \
 3   4   6
断开父节点2和4的连接 把3连接到2的右子节点 再把4连接到3的右节点

     1
     / \
   2   5
    \    \
     3   6
      \
       4

再把1和右子树5断开 把左子树2连接到1的右节点上 右子树5连接到左子树的最右节点4的右节点上

1
 \
  2
   \
    3
     \
      4
       \
        5
         \
          6
代码:

class Solution {
    public void flatten(TreeNode root) {
       if (root == null){
           return;
       }
       if (root.left != null){
           flatten(root.left);
       }
       if (root.right != null){
           flatten(root.right);
       }
       TreeNode temp = root.right;
       root.right = root.left;
       root.left = null;
       while (root.right != null){
           root = root.right;
       }
       root.right = temp;
    }
}

思路二:非递归

从根节点开始出发,先检测其左子结点是否存在,如存在则将根节点和其右子节点断开,将左子结点及其后面所有结构一起连到原右子节点的位置,把原右子节点连到原左子结点最后面的右子节点之后。过程如下:

     1
    / \
   2   5
  / \   \
 3   4   6

   1
    \
     2
    / \
   3   4
        \
         5
          \
           6
           
   1
    \
     2
      \
       3
        \
         4
          \
           5
            \
             6
class Solution {
    public void flatten(TreeNode root) {
        TreeNode temp = root;
        while (temp != null){
            if (temp.left != null){
                TreeNode temp2 = temp.left;
                while (temp2.right != null){
                    temp2 = temp2.right;
                }
                temp2.right = temp.right;
                temp.right = temp.left;
                temp.left = null;
            }
            temp = temp.right;
        }
    }
}

二、搜索二叉树转有序双链表

二叉搜索树中序遍历,然后修改左右指针的指向

调整指针:

  • 原先指向左子节点的指针调整为链表中指向前一个节点的指针
  • 原先指向右子节点的指针调整为链表中指向后一个节点的指针

如何调整:

对于这种基本情况,可以分成三个部分来看,根节点10,左子树,右子树,需要做的就是将10与左子树中的最大值连起来,然后把10与右子树中的最小值连起来,现在有个问题就是我们并不知道左子树中的最大值和右子树中的最小值。但是想到递归,递归到左子树中,如果左子树已转换为双向链表,那么双向链表的最后一个节点就是我们想要的,而右子树中的第一个节点也是我们想要的

代码:

/**
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) {
        TreeNode last = null;
        last = convertNode(pRootOfTree,last);
        //找到头节点
        TreeNode head = last;
        while (head != null && head.left != null){
            head = head.left;
        }
        return head;
    }

    private TreeNode convertNode(TreeNode pRootOfTree, TreeNode last) {
        if (pRootOfTree == null){
            return last;
        }
        TreeNode temp = pRootOfTree;
        //转换左子树
        if (temp.left != null){
            last = convertNode(temp.left, last);
        }

        //转换
        temp.left = last;
        if (last != null){
            last.right = temp;
        }
        last = temp;
        //转换右子树
        if (pRootOfTree.right != null){
            last = convertNode(temp.right, last);
        }
        return last;
    }
}

上面的代码中有两个参数,一个是根节点,一个是已经转换好的链表的最后一个节点,因为二叉搜索树中序遍历的特性,当遍历到根节点的时候,左子树已经排好序了,所以会有一个左子树已经转换好的链表,而这个链表的最后一个节点即是我们需要和根节点左连的节点

思路二:

根据中序遍历,直接进行调整:

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

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

    }

}
*/
public class Solution {
    TreeNode leftHead = null;
    TreeNode rightHead = null;
    public TreeNode Convert(TreeNode pRootOfTree) {
        //递归调用叶子节点的左右节点返回null
        if (pRootOfTree == null){
            return null;
        }
        Convert(pRootOfTree.left);
        if (rightHead == null){
            leftHead = rightHead = pRootOfTree;
        }else {
            rightHead.right = pRootOfTree;
            pRootOfTree.left = rightHead;
            rightHead = pRootOfTree;
        }
        Convert(pRootOfTree.right);
        return leftHead;
    }
}

直接定义头尾指针,一开始都指向二叉树的最左节点,然后根据中序遍历的顺序依次插入每一个节点即可

猜你喜欢

转载自blog.csdn.net/lyj2018gyq/article/details/87915799