Day12:代码随想录算法训练营第十二天| 二叉树基础 二叉树的递归迭代遍历

二叉树基础理论

1.基本二叉树分类
1.满二叉树
满二叉树就是每一层的结点都是满的,只有度为2或0的结点。
若二叉树深度为k,则易得节点总数统计结果为2^k - 1
Day12:代码随想录算法训练营第十二天| 二叉树基础 二叉树的递归迭代遍历_第1张图片
2.完全二叉树
在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。
就是说如果第n层是最低层,那么第n层的结点都均匀分布在左侧,且从1到n-1层这个二叉树是满二叉树。
有几个性质:

  1. 完全二叉树的最大深度为[log2 n] + 1。
  2. 若完全二叉树的父结点为第i个,则其左孩子是第2i 个,右孩子是第2i + 1个。
  3. 堆就是一个完全二叉树,只不过每次最大或最小的都是根节点。

Day12:代码随想录算法训练营第十二天| 二叉树基础 二叉树的递归迭代遍历_第2张图片
3.二叉搜索树
二叉搜索树是一个有序树。
它是这样定义的:
1.父节点的值大于左节点的值,小于右节点的值。
2.它的左、右子树也分别为二叉排序树。
Day12:代码随想录算法训练营第十二天| 二叉树基础 二叉树的递归迭代遍历_第3张图片
4.平衡二叉搜索树
平衡二叉搜索树是对二叉搜索树加了一定条件而定义的。
它要求一颗二叉搜索树的左右子树的深度差的绝对值只能是0或1。
这么要求主要是降低二叉搜索树的高度,提高查询效率。
Day12:代码随想录算法训练营第十二天| 二叉树基础 二叉树的递归迭代遍历_第4张图片
2.二叉树存储方式
有数组和链式两种。
一般使用链式结构:

struct BiTree{
int val;
BiTree* Left;
BiTree* Right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
}

数组的表现形式如下:
Day12:代码随想录算法训练营第十二天| 二叉树基础 二叉树的递归迭代遍历_第5张图片
3.二叉树的遍历
一共有四种遍历形式:
1.前序遍历(根左右)。
2.中序遍历(左根右)。
3.后序遍历(左右根)。
4.层次遍历。
前三种称为深度优先遍历,第四种称为广度优先遍历
可以用递归和迭代两种方式解决:
1.深度优先遍历:
迭代法:运用了栈回溯树,便于得到上一个结点,以此可以获得上一个不空节点的另一个孩子。这里以前序遍历为例子。

public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> ans = new ArrayList<>();
        //一开始就空就直接退出就行。
        if(root == null){
            return ans;
        }
        Stack<TreeNode> stack = new Stack<>();
        //因为root也可能为空,栈里却不是空的,
        //因为栈需要回溯才可得到不空的结点。
       while(root != null || !stack.isEmpty()){
          while(root != null){
      				//从根开始遍历
            ans.add(root.val); 
            //将根节点和左节点压栈
            stack.push(root);
            //遍历完后更新为左孩子,然后就是左的左,一定是先遍历玩整个左边
            root = root.left;
         }
        //出栈回溯
        //继续将栈顶元素的右孩子的左孩子继续压栈
        TreeNode node = stack.pop();
        root = node.right; 
        //空了指向右边,还空的话由上一步退栈回溯到不空为止
       }
        return ans;
    }

思考:
如果是中序呢?
中序只需要把 ans.add(root.val)放到TreeNode node = stack.pop()的下一句即可,那这样的话 while(root != null)找的就是二叉树最下层的最左侧的结点,从该节点开始记录。
如果是后序呢?
后序就直接找根右左,把root = root.left和root = node.right;换个顺序即可,然后把list顺序颠倒。
递归法
确定递归的返回值和参数、终止条件和单层递归条件。
可以把他理解为一个栈,不断地加入元素然后有退出元素,也就是最终结果会先显现出来,然后出来的是从后往前是一层层的单层结果。

中序和后序就是把ans.add(root.val)和if(root.left != null)preorderTraversal(root.left)和 if(root.right != null) preorderTraversal(root.right)的顺序改变即可。

class Solution {

    List<Integer> ans = new ArrayList<>(); //返回值
    public List<Integer> preorderTraversal(TreeNode root) { //参数
        //终止条件
        if(root == null){
            return ans;
        }
        //下面就是单层递归逻辑
        //根
        ans.add(root.val);
        //左
        if(root.left != null) preorderTraversal(root.left);
        //右
        if(root.right != null) preorderTraversal(root.right);
        return ans;
    }
}

1.广度优先遍历:
需要用到队列来解决,因为队列先进先出,保证每一层从左往右输出,每一层的结点出队时,需要将这些节点的左右孩子加进去。

public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> ans = new ArrayList<>();
        if (root == null) {
            return ans;
        }
        Queue<TreeNode> queue = new ArrayDeque<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            //记录每一层节点个数
            int size = queue.size();
            List<Integer> temp = new ArrayList<>();
            //一边将该层节点出队列,一边将节点的左右子节点加入队列,直到最后队列为空结束循环
            while (size > 0) {
                TreeNode node = queue.poll();
                temp.add(node.val);
                //将该节点的左右子节点放入队列
                if (node.left != null) queue.offer(node.left);
                if (node.right != null) queue.offer(node.right);
                size--;
            }
            ans.add(temp);
        }

        return ans;
    }

(图片代码均来自代码随想录,个人仅用于复习总结)

你可能感兴趣的:(二叉树,算法,数据结构)