1、

链表遍历分两种结构,迭代和递归。

同样根据链表可以 推导出二叉树和N叉树的遍历框架。

再由n叉树的遍历扩展到图的遍历。

手把手带你刷二叉树(第一期)
/* 二叉树遍历框架 */
void traverse(TreeNode root) {
    // 前序遍历
    traverse(root.left)
    // 中序遍历
    traverse(root.right)
    // 后序遍历
}

快速排序可以看作 二叉树的前序遍历,归并可以看作后序遍历

写递归算法的秘诀

写树相关的算法,简单说就是,先搞清楚当前 root 节点「该做什么」以及「什么时候做」,然后根据函数定义递归调用子节点,递归调用会让孩子节点做相同的事情。

所谓「该做什么」就是让你想清楚写什么代码能够实现题目想要的效果,所谓「什么时候做」,就是让你思考这段代码到底应该写在前序、中序还是后序遍历的代码位置上。

226 题-二叉树上的每一个节点的左右子节点进行交换

二叉树上的每一个节点的左右子节点进行交换

递归实现: --深度优先

转换左右孩子的时候,左右孩子的孩子已经到位了。/或者先转换左右孩子,再转换子孙

可以放在前序遍历和后续遍历的位置。

错误1:没有return 错误2,左右孩子搞反了 错误3:没有判断为空

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode invertTree(TreeNode root) {
        if (root==null){
            return null;
        }
        TreeNode tmp= root.right;
        root.right=root.left;
        root.left=tmp;
        invertTree(root.left);
        invertTree(root.right);

        return root;
    }
}

迭代实现: --广度优先

class Solution {
	public TreeNode invertTree(TreeNode root) {
		if(root==null) {
			return null;
		}
        
		//将二叉树中的节点逐层放入队列中,再迭代处理队列中的元素
		LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
		queue.add(root);
		while(!queue.isEmpty()) {
			//每次都从队列中拿一个节点,并交换这个节点的左右子树
			TreeNode tmp = queue.poll();
			TreeNode left = tmp.left;
			tmp.left = tmp.right;
			tmp.right = left;
			//如果当前节点的左子树不为空,则放入队列等待后续处理
			if(tmp.left!=null) {
				queue.add(tmp.left);
			}
			//如果当前节点的右子树不为空,则放入队列等待后续处理
			if(tmp.right!=null) {
				queue.add(tmp.right);
			}	
		}
		//返回处理完的根节点
		return root;
	}
}

LinkedList创建: LinkedList<TreeNode> queue = new LinkedList<TreeNode>(); ( )别忘了

poll 删除返回第一个元素,add加入一个元素。

解析: 当换完左右子树后,再对孙子节点交换,也就是队列中推入孩子节点

注意: 循环退出的条件,然后循环里面要干什么:用临时变量交换左右孩子。 tmp是某一个根节点

错误:要用while不能用 if

116. 填充每个节点的下一个右侧节点指针

tips: 转换为节点要做的事情,这里设置为两个节点。

方法1:递归函数法

从根节点开始,定义函数conect_two 。 如果connect的两个节点不为空,就连接。

left.left - left.right /left.right --right.left /right.left-right.right

class Solution {
    public Node connect(Node root) {
        if(root==null){
            return null; }

        connectTwo(root.left,root.right);

        return root;
    }
    public void connectTwo(Node first,Node second){
        if(first==null || second==null ){
            return ; //不是null
        }
        first.next=second;
        connectTwo(first.left,first.right);
        connectTwo(first.right,second.left);
        connectTwo(second.left,second.right);
        return;
    } 

}

错误: 忘记了 first.next=second; 即本层忘了连接了。 函数可以不加public。

方法2递归

两个指针,从根节点开始往中间靠拢,直到最后一层。

class Solution {
	public Node connect(Node root) {
		dfs(root);
		return root;
	}
	
	void dfs(Node root) {
		if(root==null) {
			return;
		}
		Node left = root.left;
		Node right = root.right;
		//配合动画演示理解这段,以root为起点,将整个纵深这段串联起来
		while(left!=null) {
			left.next = right;
			left = left.right;
			right = right.left;
		}
		//递归的调用左右节点,完成同样的纵深串联
		dfs(root.left);
		dfs(root.right);
	}
}

方法3 迭代

一种是有共同父节点,可以直接填充下一个。一种是跨了父节点,可以通过上一层的串联来获得next即为root.right.next => root.next.left

class Solution {
	public Node connect(Node root) {
		if(root==null) {
			return root;
		}
		Node pre = root;
		//循环条件是当前节点的left不为空,当只有根节点
		//或所有叶子节点都出串联完后循环就退出了
		while(pre.left!=null) {
			Node tmp = pre;
			while(tmp!=null) {
				//将tmp的左右节点都串联起来
				//注:外层循环已经判断了当前节点的left不为空
				tmp.left.next = tmp.right;
				//下一个不为空说明上一层已经帮我们完成串联了
				if(tmp.next!=null) {
					tmp.right.next = tmp.next.left;
				}
				//继续右边遍历
				tmp = tmp.next;
			}
			//从下一层的最左边开始遍历
			pre = pre.left;
		}
		return root;
	}
}

114. 二叉树展开为链表

假设左右子树已经拉直了

同样用递归的方法,假设左右子树已经拉直了。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public void flatten(TreeNode root) {
        if (root==null){
            return ;
        }
        flatten(root.left);
        flatten(root.right);
        //错了
        // root.left.right=root.right;
        // root.right=root.left;
        // root.left=null;   这里把p 设置为根节点比较好,否则p会为空
        TreeNode left_=root.left;
        TreeNode right_=root.right;
        root.right=left_;
        TreeNode p=root;
        while(p.right!=null){
            p=p.right;
        }
        p.right=right_;
        root.left=null;
        
    }

错误: 把左子树放到右孩子后, 原来的右子树要 放在 最下节点(要一直遍历到下面) 的右边

左子树要置空

迭代的方法

将左子树放到右子树的位置,右子树放到左子树的最右下。

public void flatten(TreeNode root) {
    while (root != null) { 
        //左子树为 null,直接考虑下一个节点
        if (root.left == null) {
            root = root.right;
        } else {
            // 找左子树最右边的节点
            TreeNode pre = root.left;
            while (pre.right != null) {
                pre = pre.right;
            } 
            //将原来的右子树接到左子树的最右边节点
            pre.right = root.right;
            // 将左子树插入到右子树的地方
            root.right = root.left;
            root.left = null;
            // 考虑下一个节点
            root = root.right;
        }
    }
}

关键: 找到右子树的前驱节点 然后再考虑 下一个节点root = root.right;

类后序遍历

其实要做的是前序遍历的结果倒过来,1-2-3-4-5-6 到6-5-4-3-2-1

遍历顺序 右 左 中。

https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by--26/

--- 还有一种解,先略过。

手把手带你刷二叉树(第二期)

654. 最大二叉树

class Solution {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
     return  construct(nums,0,nums.length-1);  //可以直接return
    }
    public TreeNode construct(int[] nums,int left,int right){
        TreeNode root;
        // if (left>right || left==right){
        //     root =new TreeNode(nums[left],null,null);
        //     //这里不能用left 或者right ,  直接改成 low>high返回null
        //     return root;
        // }
        if (left>right){
            return null;
        }
        if(left<right || left==right){
        int index = findMax(nums,left,right);
        root =new TreeNode(nums[index]);
        root.left=construct(nums,left,index-1);
        root.right=construct(nums,index+1,right);
        return root;
        }
        return null;
    }
 //不是 0改成 最小值,其次要改成小于等于,index是-1
    public int findMax (int[] nums,int l,int r){
        if (l==r){
            return l;
        }
        int max =Integer.MIN_VALUE; int index =0;
        for (int i=l;i<=r;i++){
            if (nums[i]>max){
                max=nums[i];
                index=i;
            }
        }
        return index;
    }
}

数组参数: .length 可以获得长度 最小值:Integer.MIN_VALUE

问题:

判断节点条件,可以把子右孩子看作节点单独判断,若left>right则返回空,这样比较好处理

其次,索引i<=r,因为传入的就是length-1

105通过前序和中序遍历结果构造二叉树

递归版本

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
      return construct(preorder,inorder,0,preorder.length-1,0,inorder.length-1);
    }
    public TreeNode construct(int[] pre,int[] ino,int left_1,int right_1,int left_2,int right_2)
    {
        int index=0;
        TreeNode root=new TreeNode(); //注意要初始化
        if (left_1 >right_1){
            return null;
        }
        
        int root_val=pre[left_1];
       
        for(int i=left_2;i<=right_2;i++){
            if (ino[i]==root_val){
                index=i;
                break;
                //加个break
          
        }
        //错误2:index-left2 =size,不用+1
        int size =index-left_2;
        root.val=root_val;
        root.left=construct(pre,ino,left_1+1,left_1+size,left_2,index-1);
        root.right=construct(pre,ino,left_1+1+size,right_1,index+1,right_2 );

        return root;
    }
}

问题:

找index时,可以加个break加快速度。 其次是算size时不用+1。 最后变量注意要初始化

迭代版本

补充

给一个随机数组,生成相应的二叉搜索树

https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/

根据前序和中序,输出后序